diff options
author | Gabor X Toth <*@tg-x.net> | 2015-12-17 14:12:44 +0000 |
---|---|---|
committer | Gabor X Toth <*@tg-x.net> | 2015-12-17 14:12:44 +0000 |
commit | c159ab01bd16e9f3ad1776fa6fb26398cb7986d9 (patch) | |
tree | 61b0cad0b3e94f7e2dc7a8b48de7dc24784e229d | |
parent | 6cf89fa848bbcb9e1f941bad1ac0c4ec6066fdd7 (diff) |
social: API changes for application connections: store/load app subscriptions to places
-rw-r--r-- | src/include/gnunet_gnsrecord_lib.h | 2 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 30 | ||||
-rw-r--r-- | src/include/gnunet_social_service.h | 485 | ||||
-rw-r--r-- | src/social/Makefile.am | 9 | ||||
-rw-r--r-- | src/social/gnunet-service-social.c | 1361 | ||||
-rw-r--r-- | src/social/social.h | 181 | ||||
-rw-r--r-- | src/social/social_api.c | 1233 | ||||
-rw-r--r-- | src/social/test_social.c | 356 |
8 files changed, 2664 insertions, 993 deletions
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h index d52054909f..76eb69a8a4 100644 --- a/src/include/gnunet_gnsrecord_lib.h +++ b/src/include/gnunet_gnsrecord_lib.h @@ -195,7 +195,7 @@ struct GNUNET_GNSRECORD_PlaceData /** * Public key of the place. */ - struct GNUNET_CRYPTO_EddsaPublicKey place_key; + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; /** * Peer identity of the origin. diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 5ae4403492..d6b9c50843 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2607,18 +2607,38 @@ extern "C" /** C->S: request to enter a place as a guest */ #define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER 843 +/** C->S: request to enter a place as a guest, using a GNS address */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME 844 + /** S->C: guest enter acknowledgement */ -#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK 844 +#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK 845 /** P->S->C: incoming entry request from PSYC */ -#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_REQUEST 845 +#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_REQUEST 846 /** C->S->P: decision about an entry request */ -#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_DECISION 846 +#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_DECISION 847 + +/** C->S: request to leave a place */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE 848 + +/** C->S: add place to GNS zone */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE 849 + +/** C->S: add nym to GNS zone */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM 850 + +/** C->S: connect application */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT 851 + +/** C->S: detach a place from application */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH 852 -/** C->S: listen for places */ -#define GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN 850 +/** S->C: notify about an existing ego */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO 853 +/** S->C: notify about an existing place */ +#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE 854 /******************************************************************************* * X-VINE DHT messages diff --git a/src/include/gnunet_social_service.h b/src/include/gnunet_social_service.h index 21c073256e..47062fdafd 100644 --- a/src/include/gnunet_social_service.h +++ b/src/include/gnunet_social_service.h @@ -48,6 +48,20 @@ extern "C" */ #define GNUNET_SOCIAL_VERSION 0x00000000 +/** + * Maximum size of client ID including '\0' terminator. + */ +#define GNUNET_SOCIAL_APP_MAX_ID_SIZE 256 + +/** + * Handle for an application. + */ +struct GNUNET_SOCIAL_App; + +/** + * Handle for an ego (own identity) + */ +struct GNUNET_SOCIAL_Ego; /** * Handle for a pseudonym of another user in the network. @@ -74,6 +88,144 @@ struct GNUNET_SOCIAL_Guest; */ struct GNUNET_SOCIAL_Slicer; + + + +/** + * Handle that can be used to reconnect to a place as host. + */ +struct GNUNET_SOCIAL_HostConnection; + +/** + * Handle that can be used to reconnect to a place as guest. + */ +struct GNUNET_SOCIAL_GuestConnection; + +/** + * Notification about an available identity. + * + * @param cls + * Closure. + * @param pub_key + * Public key of ego. + * @param name + * Name of ego. + */ +typedef void +(*GNUNET_SOCIAL_AppEgoCallback) (void *cls, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, + const char *name); + + +/** + * Notification about a place entered. + */ +typedef void +(*GNUNET_SOCIAL_AppHostPlaceCallback) (void *cls, + struct GNUNET_SOCIAL_HostConnection *hconn, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key); + +/** +h * Notification about a place entered. + */ +typedef void +(*GNUNET_SOCIAL_AppGuestPlaceCallback) (void *cls, + struct GNUNET_SOCIAL_GuestConnection *gconn, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key); + + +/** + * Establish application connection to the social service. + * + * The @host_place_cb and @guest_place_cb functions are + * initially called for each entered places, + * then later each time a new place is entered with the current app ID. + * + * @param cfg + * Configuration. + * @param ego_cb + * Function to notify about an available ego. + * @param host_cb + * Function to notify about a place entered as host. + * @param guest_cb + * Function to notify about a place entered as guest. + * @param cls + * Closure for the callbacks. + * + * @return Handle that can be used to stop listening. + */ +struct GNUNET_SOCIAL_App * +GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *id, + GNUNET_SOCIAL_AppEgoCallback ego_cb, + GNUNET_SOCIAL_AppHostPlaceCallback host_cb, + GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, + void *cls); + + +/** + * Disconnect app. + * + * @param c + * App handle. + */ +void +GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app); + + +/** + * Get the public key of @a ego. + * + * @param ego + * Ego. + * + * @return Public key of ego. + */ +const struct GNUNET_CRYPTO_EcdsaPublicKey * +GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego); + + +/** + * Get the name of @a ego. + * + * @param ego + * Ego. + * + * @return Public key of @a ego. + */ +const char * +GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego); + + +/** + * Get the public key of a @a nym. + * + * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). + * + * @param nym + * Pseudonym to map to a cryptographic identifier. + * + * @return Public key of nym. + */ +const struct GNUNET_CRYPTO_EcdsaPublicKey * +GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym); + + +/** + * Get the hash of the public key of a @a nym. + * + * @param nym + * Pseudonym to map to a cryptographic identifier. + * + * @return Hash of the public key of nym. + */ +const struct GNUNET_HashCode * +GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym); + + /** * Function called upon receiving a message indicating a call to a @e method. * @@ -352,19 +504,22 @@ typedef void /** - * Function called after the host entered the place. + * Function called after the host entered a home. * * @param cls * Closure. * @param result * #GNUNET_OK on success, or * #GNUNET_SYSERR on error. + * @param place_pub_key + * Public key of home. * @param max_message_id * Last message ID sent to the channel. * Or 0 if no messages have been sent to the place yet. */ typedef void (*GNUNET_SOCIAL_HostEnterCallback) (void *cls, int result, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, uint64_t max_message_id); @@ -385,6 +540,8 @@ typedef void * Policy specifying entry and history restrictions for the place. * @param slicer * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. * @param answer_door_cb * Function to handle new nyms that want to enter. * @param farewell_cb @@ -395,9 +552,8 @@ typedef void * @return Handle for the host. */ struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key, +GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, enum GNUNET_PSYC_Policy policy, struct GNUNET_SOCIAL_Slicer *slicer, GNUNET_SOCIAL_HostEnterCallback enter_cb, @@ -407,6 +563,34 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, /** + * Reconnect to an already entered place as host. + * + * @param hconn + * Host connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() + * @param slicer + * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. + * @param answer_door_cb + * Function to handle new nyms that want to enter. + * @param farewell_cb + * Function to handle departing nyms. + * @param cls + * Closure for the callbacks. + * + * @return Handle for the host. + */ +struct GNUNET_SOCIAL_Host * +GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, + struct GNUNET_SOCIAL_Slicer *slicer, + GNUNET_SOCIAL_HostEnterCallback enter_cb, + GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, + GNUNET_SOCIAL_FarewellCallback farewell_cb, + void *cls); + + +/** * Decision whether to admit @a nym into the place or refuse entry. * * @param hst @@ -438,6 +622,8 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, /** * Throw @a nym out of the place. * + * Sends a _notice_place_leave announcement to the home. + * * The @a nym reference will remain valid until the * #GNUNET_SOCIAL_FarewellCallback is invoked, * which should be very soon after this call. @@ -446,69 +632,14 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, * Host of the place. * @param nym * Handle for the entity to be ejected. + * @param env + * Environment for the message or NULL. + * _nym is set to @e nym regardless whether an @e env is provided. */ void GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host, - const struct GNUNET_SOCIAL_Nym *nym); - - -/** - * Get the public key of a @a nym. - * - * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name(). - * - * @param nym - * Pseudonym to map to a cryptographic identifier. - * - * @return Public key of nym. - */ -const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym); - - -/** - * Get the hash of the public key of a @a nym. - * - * @param nym - * Pseudonym to map to a cryptographic identifier. - * - * @return Hash of the public key of nym. - */ -const struct GNUNET_HashCode * -GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym); - - -/** - * Advertise the place in the GNS zone of the @e ego of the @a host. - * - * @param hst - * Host of the place. - * @param name - * The name for the PLACE record to put in the zone. - * @param peer_count - * Number of elements in the @a peers array. - * @param peers - * List of peers to put in the PLACE record to advertise - * as entry points to the place in addition to the origin. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param password - * Password used to encrypt the record. - * FIXME: not implemented yet. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb - */ -void -GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *host, - const char *name, - uint32_t peer_count, - const struct GNUNET_PeerIdentity *peers, - struct GNUNET_TIME_Absolute expiration_time, - const char *password, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls); + const struct GNUNET_SOCIAL_Nym *nym, + struct GNUNET_ENV_Environment *env); /** @@ -602,25 +733,44 @@ GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host); /** - * Stop hosting a place. + * Disconnect from a home. * * Invalidates host handle. * - * @param host - * Host leaving the place. - * @param keep_active - * Keep the place active after last host disconnected. - * @param leave_cb + * @param hst + * The host to disconnect. + * @param disconnect_cb + * Function called after disconnected from the service. + * @param cls + * Closure for @a disconnect_cb. + */ +void +GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls); + + +/** + * Stop hosting a home. + * + * Sends a _notice_place_closed announcement to the home. + * Invalidates host handle. + * + * @param hst + * Host leaving. + * @param env + * Environment for the message or NULL. + * @param disconnect_cb * Function called after the host left the place - * and disconnected from the social service. - * @param leave_cls - * Closure for @a leave_cb. + * and disconnected from the service. + * @param cls + * Closure for @a disconnect_cb. */ void -GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host, - int keep_active, - GNUNET_ContinuationCallback leave_cb, - void *leave_cls); +GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, + const struct GNUNET_ENV_Environment *env, + GNUNET_ContinuationCallback disconnect_cb, + void *cls); /** @@ -689,9 +839,9 @@ typedef void * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, +GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, const struct GNUNET_PeerIdentity *origin, uint32_t relay_count, const struct GNUNET_PeerIdentity *relays, @@ -729,9 +879,10 @@ GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *gns_name, const char *password, +GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *gns_name, + const char *password, const struct GNUNET_PSYC_Message *join_msg, struct GNUNET_SOCIAL_Slicer *slicer, GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, @@ -740,6 +891,28 @@ GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg /** + * Reconnect to an already entered place as guest. + * + * @param gconn + * Guest connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() + * @param slicer + * Slicer to use for processing incoming requests from guests. + * @param local_enter_cb + * Called upon connection established to the social service. + * @param entry_decision_cb + * Called upon receiving entry decision. + * + * @return NULL on errors, otherwise handle for the guest. + */ +struct GNUNET_SOCIAL_Guest * +GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, + struct GNUNET_SOCIAL_Slicer *slicer, + GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, + void *cls); + + +/** * Flags for talking to the host of a place. */ enum GNUNET_SOCIAL_TalkFlags @@ -803,26 +976,40 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr); /** + * Disconnect from a place. + * + * Invalidates guest handle. + * + * @param gst + * The guest to disconnect. + * @param disconnect_cb + * Function called after disconnected from the service. + * @param cls + * Closure for @a disconnect_cb. + */ +void +GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls); + + +/** * Leave a place temporarily or permanently. * * Notifies the owner of the place about leaving, and destroys the place handle. * * @param place * Place to leave. - * @param keep_active - * Keep place active after last application disconnected. - * #GNUNET_YES or #GNUNET_NO * @param env * Optional environment for the leave message if @a keep_active * is #GNUNET_NO. NULL if not needed. - * @param leave_cb + * @param disconnect_cb * Called upon disconnecting from the social service. */ void GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, - int keep_active, struct GNUNET_ENV_Environment *env, - GNUNET_ContinuationCallback leave_cb, + GNUNET_ContinuationCallback disconnect_cb, void *leave_cls); @@ -974,96 +1161,76 @@ GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh); /** - * Add public key to the GNS zone of the @e ego. + * Advertise a @e place in the GNS zone of @a ego. * - * @param cfg - * Configuration. + * @param app + * Application handle. * @param ego * Ego. + * @param place_pub_key + * Public key of place to add. * @param name - * The name for the PKEY record to put in the zone. - * @param nym_pub_key - * Public key of nym to add. + * The name for the PLACE record to put in the zone. + * @param password + * Password used to encrypt the record or NULL to keep it cleartext. + * @param relay_count + * Number of elements in the @a relays array. + * @param relays + * List of relays to put in the PLACE record to advertise + * as entry points to the place in addition to the origin. * @param expiration_time * Expiration time of the record, use 0 to remove the record. * @param result_cb * Function called with the result of the operation. * @param result_cls * Closure for @a result_cb + * + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name/password is too long. */ -void -GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls); - - -/** - * Handle for place notifications. - */ -struct GNUNET_SOCIAL_PlaceListenHandle; - - -/** - * Notification about a place entered as host. - */ -typedef void -(*GNUNET_SOCIAL_PlaceNotifyHostCallback) (void *cls, - const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key, - enum GNUNET_PSYC_Policy policy); - - -/** - * Notification about a place entered as guest. - */ -typedef void -(*GNUNET_SOCIAL_PlaceNotifyGuestCallback) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *entry_msg); +int +GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const char *password, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, + const struct GNUNET_PeerIdentity *origin, + uint32_t relay_count, + const struct GNUNET_PeerIdentity *relays, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls); /** - * Start listening for entered places as host or guest. - * - * The @notify_host and @notify_guest functions are - * initially called with the full list of entered places, - * then later each time a new place is entered. + * Add public key to the GNS zone of the @e ego. * * @param cfg * Configuration. * @param ego - * Listen for places of this ego. - * @param notify_host - * Function to notify about a place entered as host. - * @param notify_guest - * Function to notify about a place entered as guest.. - * @param notify_cls - * Closure for the callbacks. - * - * @return Handle that can be used to stop listening. - */ -struct GNUNET_SOCIAL_PlaceListenHandle * -GNUNET_SOCIAL_place_listen_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - GNUNET_SOCIAL_PlaceNotifyHostCallback notify_host, - GNUNET_SOCIAL_PlaceNotifyGuestCallback notify_guest, - void *notify_cls); - - -/** - * Stop listening for entered places. + * Ego. + * @param name + * The name for the PKEY record to put in the zone. + * @param nym_pub_key + * Public key of nym to add. + * @param expiration_time + * Expiration time of the record, use 0 to remove the record. + * @param result_cb + * Function called with the result of the operation. + * @param result_cls + * Closure for @a result_cb * - * @param h - * Listen handle. + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name is too long. */ -void -GNUNET_SOCIAL_place_listen_stop (struct GNUNET_SOCIAL_PlaceListenHandle *h); +int +GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls); #if 0 /* keep Emacsens' auto-indent happy */ diff --git a/src/social/Makefile.am b/src/social/Makefile.am index 2c8d5707da..ac80d0c8ce 100644 --- a/src/social/Makefile.am +++ b/src/social/Makefile.am @@ -25,11 +25,6 @@ libgnunetsocial_la_SOURCES = \ libgnunetsocial_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/env/libgnunetenv.la \ - $(top_builddir)/src/psycstore/libgnunetpsycutil.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/gns/libgnunetgns.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) $(XLIB) libgnunetsocial_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ @@ -47,6 +42,10 @@ gnunet_service_social_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/psyc/libgnunetpsyc.la \ $(top_builddir)/src/psycstore/libgnunetpsycutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c index aace01fed9..b7cf1f8567 100644 --- a/src/social/gnunet-service-social.c +++ b/src/social/gnunet-service-social.c @@ -25,11 +25,16 @@ */ #include <inttypes.h> +#include <strings.h> #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" +#include "gnunet_core_service.h" +#include "gnunet_identity_service.h" +#include "gnunet_namestore_service.h" +#include "gnunet_gns_service.h" #include "gnunet_statistics_service.h" #include "gnunet_psyc_service.h" #include "gnunet_psyc_util_lib.h" @@ -42,10 +47,17 @@ */ static const struct GNUNET_CONFIGURATION_Handle *cfg; +/* Handles to other services */ +static struct GNUNET_CORE_Handle *core; +static struct GNUNET_IDENTITY_Handle *id; +static struct GNUNET_GNS_Handle *gns; +static struct GNUNET_NAMESTORE_Handle *namestore; +static struct GNUNET_STATISTICS_Handle *stats; + /** - * Handle to the statistics service. + * ID of this peer. */ -static struct GNUNET_STATISTICS_Handle *stats; +static struct GNUNET_PeerIdentity this_peer; /** * Notification context, simplifies client broadcasts. @@ -66,7 +78,7 @@ static struct GNUNET_CONTAINER_MultiHashMap *guests; /** * Connected guests per place. - * H(place_pub_key) -> Guest's pub_key -> struct Guest + * H(place_pub_key) -> ego_pub_key -> struct Guest */ static struct GNUNET_CONTAINER_MultiHashMap *place_guests; @@ -74,19 +86,44 @@ static struct GNUNET_CONTAINER_MultiHashMap *place_guests; * Places entered as host or guest. * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest */ -static struct GNUNET_CONTAINER_MultiHashMap *places_entered; +static struct GNUNET_CONTAINER_MultiHashMap *places; + +/** + * Places entered per application. + * H(app_id) -> H(place_pub_key) -> NULL + */ +static struct GNUNET_CONTAINER_MultiHashMap *apps_places; + +/** + * Connected applications. + * H(app_id) -> struct Application + */ +static struct GNUNET_CONTAINER_MultiHashMap *apps; + +/** + * All egos. + * H(ego_pub_key) -> struct Ego + */ +static struct GNUNET_CONTAINER_MultiHashMap *egos; /** - * Place listener clients. - * H(ego_pub_key) -> struct PlaceListener + * Directory for storing social data. + * Default: ~/.local/share/gnunet/social */ -static struct GNUNET_CONTAINER_MultiHashMap *place_listeners; +static char *dir_social; /** - * Directory for storing places. + * Directory for storing place data. + * $dir_social/places */ static char *dir_places; +/** + * Directory for storing app data. + * $dir_social/apps + */ +static char *dir_apps; + /** * Message fragment transmission queue. @@ -157,7 +194,12 @@ struct Place struct GNUNET_PSYC_Channel *channel; /** - * Public key of the channel. + * Private key of home in case of a host. + */ + struct GNUNET_CRYPTO_EddsaPublicKey key; + + /** + * Public key of place. */ struct GNUNET_CRYPTO_EddsaPublicKey pub_key; @@ -167,6 +209,21 @@ struct Place struct GNUNET_HashCode pub_key_hash; /** + * Private key of ego. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; + + /** + * Public key of ego. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + /** + * Hash of @a ego_pub_key. + */ + struct GNUNET_HashCode ego_pub_hash; + + /** * Last message ID received for the place. * 0 if there is no such message. */ @@ -202,11 +259,6 @@ struct Host struct Place plc; /** - * Private key of the channel. - */ - struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; - - /** * Handle for the multicast origin. */ struct GNUNET_PSYC_Master *master; @@ -240,21 +292,6 @@ struct Guest struct Place plc; /** - * Private key of the slave. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * Public key of the slave. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** * Handle for the PSYC slave. */ struct GNUNET_PSYC_Slave *slave; @@ -293,7 +330,7 @@ struct Guest /** - * Context for host/guest client. + * Context for a client. */ struct Client { @@ -309,19 +346,25 @@ struct Client struct MessageTransmitQueue *tmit_msg; /** - * Ego key for listener clients; + * ID for application clients. */ - struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; + char *app_id; }; -struct PlaceListener +struct Application { struct ClientListItem *clients_head; struct ClientListItem *clients_tail; }; +struct Ego { + struct GNUNET_CRYPTO_EcdsaPrivateKey key; + char *name; +}; + + struct OperationClosure { struct GNUNET_SERVER_Client *client; @@ -335,6 +378,18 @@ static int psyc_transmit_message (struct Place *plc); +static void +cleanup_place (struct Place *plc); + + +int +place_entry_cleanup (void *cls, const struct GNUNET_HashCode *key, void *value) +{ + cleanup_place (value); + return GNUNET_YES; +} + + /** * Task run during shutdown. * @@ -344,11 +399,34 @@ psyc_transmit_message (struct Place *plc); static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL); + GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL); + if (NULL != nc) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } + if (NULL != core) + { + GNUNET_CORE_disconnect (core); + core = NULL; + } + if (NULL != id) + { + GNUNET_IDENTITY_disconnect (id); + id = NULL; + } + if (NULL != namestore) + { + GNUNET_NAMESTORE_disconnect (namestore); + namestore = NULL; + } + if (NULL != gns) + { + GNUNET_GNS_disconnect (gns); + gns = NULL; + } if (NULL != stats) { GNUNET_STATISTICS_destroy (stats, GNUNET_YES); @@ -383,7 +461,7 @@ cleanup_guest (struct Guest *gst) plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &plc->pub_key_hash); GNUNET_assert (NULL != plc_gst); // FIXME - GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst); + GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst); if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst)) { @@ -444,15 +522,20 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) ctx = GNUNET_SERVER_client_get_user_context (client, struct Client); if (NULL == ctx) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p User context is NULL in client_disconnect()\n", ctx); - GNUNET_break (0); return; } struct Place *plc = ctx->plc; + + if (NULL != ctx->app_id) + GNUNET_free (ctx->app_id); + + GNUNET_free (ctx); + if (NULL == plc) - return; // place listener client, nothing to do + return; // application client, nothing to do GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p Client (%s) disconnected from place %s\n", @@ -470,40 +553,35 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) } cli = cli->next; } +} - if (NULL == plc->clients_head) - { /* Last client disconnected. */ - if (GNUNET_YES != plc->is_disconnected) - { - plc->is_disconnected = GNUNET_YES; - if (NULL != plc->tmit_msgs_head) - { /* Send pending messages to PSYC before cleanup. */ - psyc_transmit_message (plc); - } - else - { - cleanup_place (plc); - } - } - } + +/** + * Send message to a client. + */ +static inline void +client_send_msg (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_SERVER_notification_context_unicast (nc, client, msg, GNUNET_NO); } /** - * Send message to all clients connected to the channel. + * Send message to all clients connected to a place. */ static void -client_send_msg (const struct Place *plc, +place_send_msg (const struct Place *plc, const struct GNUNET_MessageHeader *msg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending message to clients.\n", plc); + "%p Sending message to clients of place.\n", plc); struct ClientListItem *cli = plc->clients_head; while (NULL != cli) { - GNUNET_SERVER_notification_context_add (nc, cli->client); - GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, GNUNET_NO); + client_send_msg (cli->client, msg); cli = cli->next; } } @@ -542,13 +620,31 @@ client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id, "%" PRId64 " (size: %u)\n", client, GNUNET_ntohll (op_id), result_code, data_size); - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, &res->header, - GNUNET_NO); + client_send_msg (client, &res->header); GNUNET_free (res); } +static void +client_send_host_enter_ack (struct GNUNET_SERVER_Client *client, + struct Host *hst, uint32_t result) +{ + struct Place *plc = &hst->plc; + + struct HostEnterAck hack; + hack.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK); + hack.header.size = htons (sizeof (hack)); + hack.result_code = htonl (result); + hack.max_message_id = GNUNET_htonll (plc->max_message_id); + hack.place_pub_key = plc->pub_key; + + if (NULL != client) + client_send_msg (client, &hack.header); + else + place_send_msg (plc, &hack.header); +} + + /** * Called after a PSYC master is started. */ @@ -560,13 +656,7 @@ psyc_master_started (void *cls, int result, uint64_t max_message_id) plc->max_message_id = max_message_id; plc->is_ready = GNUNET_YES; - struct GNUNET_PSYC_CountersResultMessage res; - res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK); - res.header.size = htons (sizeof (res)); - res.result_code = htonl (result); - res.max_message_id = GNUNET_htonll (plc->max_message_id); - - client_send_msg (plc, &res.header); + client_send_host_enter_ack (NULL, hst, result); } @@ -585,7 +675,7 @@ psyc_recv_join_request (void *cls, GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - client_send_msg (&hst->plc, &req->header); + place_send_msg (&hst->plc, &req->header); } @@ -606,7 +696,7 @@ psyc_slave_connected (void *cls, int result, uint64_t max_message_id) res.result_code = htonl (result); res.max_message_id = GNUNET_htonll (plc->max_message_id); - client_send_msg (plc, &res.header); + place_send_msg (plc, &res.header); } @@ -620,7 +710,7 @@ psyc_recv_join_dcsn (void *cls, const struct GNUNET_PSYC_Message *join_msg) { struct Guest *gst = cls; - client_send_msg (&gst->plc, &dcsn->header); + place_send_msg (&gst->plc, &dcsn->header); } @@ -641,7 +731,7 @@ psyc_recv_message (void *cls, plc, ntohs (msg->header.size), str); GNUNET_free (str); - client_send_msg (plc, &msg->header); + place_send_msg (plc, &msg->header); /* FIXME: further processing */ } @@ -656,110 +746,219 @@ place_init (struct Place *plc) } +/** + * Add a place to the @e places hash map. + * + * @param ereq + * Entry request. + * + * @return #GNUNET_OK if the place was added + * #GNUNET_NO if the place already exists in the hash map + * #GNUNET_SYSERR on error + */ +static int +place_add (const struct PlaceEnterRequest *ereq) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding place to hashmap:\n"); + + struct EgoPlacePublicKey ego_place_pub_key = { + .ego_pub_key = ereq->ego_pub_key, + .place_pub_key = ereq->place_pub_key, + }; + struct GNUNET_HashCode ego_place_pub_hash; + GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); + + struct GNUNET_MessageHeader * + place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash); + if (NULL != place_msg) + return GNUNET_NO; + + place_msg = GNUNET_copy_message (&ereq->header); + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + GNUNET_break (0); + GNUNET_free (place_msg); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} /** - * Add place to places_entered hash map. + * Add a place to the @e app_places hash map. * - * @param ego_pub_hash - * H(ego_pub_key) - * @param place_pub_hash - * H(place_pub_key) + * @param app_id + * Application ID. * @param msg * Entry message. * - * @return Return value of GNUNET_CONTAINER_multihashmap_put () + * @return #GNUNET_OK if the place was added + * #GNUNET_NO if the place already exists in the hash map + * #GNUNET_SYSERR on error */ static int -place_add (const struct GNUNET_HashCode *ego_pub_hash, - const struct GNUNET_HashCode *place_pub_hash, - const struct GNUNET_MessageHeader *msg) +app_place_add (const char *app_id, + const struct PlaceEnterRequest *ereq) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding place to hashmap:\n"); + "Adding app place to hashmap:\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " ego_pub_hash = %s\n", GNUNET_h2s (ego_pub_hash)); + " app_id = %s\n", app_id); + + struct GNUNET_HashCode app_id_hash; + GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); + + struct EgoPlacePublicKey ego_place_pub_key = { + .ego_pub_key = ereq->ego_pub_key, + .place_pub_key = ereq->place_pub_key, + }; + struct GNUNET_HashCode ego_place_pub_hash; + GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " place_pub_hash = %s\n", GNUNET_h2s (place_pub_hash)); + " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); struct GNUNET_CONTAINER_MultiHashMap * - ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, ego_pub_hash); - if (NULL == ego_places) + app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); + if (NULL == app_places) { - ego_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_CONTAINER_multihashmap_put (places_entered, ego_pub_hash, ego_places, + app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } - struct GNUNET_MessageHeader *msg_old, *msg_new; - if (NULL != (msg_old = GNUNET_CONTAINER_multihashmap_get (ego_places, place_pub_hash))) + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash)) + return GNUNET_NO; + + if (GNUNET_SYSERR == place_add (ereq)) + return GNUNET_SYSERR; + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, + NULL, 0)) { - GNUNET_free (msg_old); - GNUNET_CONTAINER_multihashmap_remove_all (ego_places, place_pub_hash); + GNUNET_break (0); + return GNUNET_SYSERR; } - uint16_t msg_size = ntohs (msg->size); - msg_new = GNUNET_malloc (msg_size); - memcpy (msg_new, msg, msg_size); - int ret = GNUNET_CONTAINER_multihashmap_put (ego_places, place_pub_hash, msg_new, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - if (GNUNET_OK != ret) - GNUNET_break (0); - return ret; + return GNUNET_OK; } /** * Save place entry message to disk. * - * @param ego_key - * Private key of ego. - * @param place_pub_hash - * Hash of public key of place. + * @param app_id + * Application ID. * @param msg * Entry message. */ -static void -place_save (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_key, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub, - const struct GNUNET_MessageHeader *msg) +static int +app_place_save (const char *app_id, + const struct PlaceEnterRequest *ereq) { + app_place_add (app_id, ereq); + if (NULL == dir_places) - return; + return GNUNET_SYSERR; + struct GNUNET_HashCode ego_pub_hash; struct GNUNET_HashCode place_pub_hash; - GNUNET_CRYPTO_hash (place_pub, sizeof (place_pub), &place_pub_hash); + GNUNET_CRYPTO_hash (&ereq->ego_pub_key, sizeof (ereq->ego_pub_key), + &ego_pub_hash); + GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key), + &place_pub_hash); + + struct GNUNET_CRYPTO_HashAsciiEncoded ego_pub_hash_ascii; + struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii; + memcpy (&ego_pub_hash_ascii.encoding, + GNUNET_h2s_full (&ego_pub_hash), sizeof (ego_pub_hash_ascii)); + memcpy (&place_pub_hash_ascii.encoding, + GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii)); + + char *filename = NULL; + GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", + dir_social, DIR_SEPARATOR, + "places", DIR_SEPARATOR, + ego_pub_hash_ascii.encoding, DIR_SEPARATOR, + place_pub_hash_ascii.encoding); + int ret = GNUNET_DISK_directory_create_for_file (filename); + if (GNUNET_OK != ret + || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size), + GNUNET_DISK_PERM_USER_READ + | GNUNET_DISK_PERM_USER_WRITE)) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + } + GNUNET_free (filename); - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub; - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_ecdsa_key_get_public (ego_key, &ego_pub); - GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash); - - place_add (&ego_pub_hash, &place_pub_hash, msg); - - char *ego_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1); - char *place_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1); - memcpy (ego_pub_hash_str, GNUNET_h2s_full (&ego_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); - memcpy (place_pub_hash_str, GNUNET_h2s_full (&place_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); - - char *filename = GNUNET_malloc (strlen (dir_places) + 1 - + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1 - + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1); - GNUNET_asprintf (&filename, - "%s%s%s%s%s", - dir_places, DIR_SEPARATOR_STR, - ego_pub_hash_str, DIR_SEPARATOR_STR, - place_pub_hash_str); + if (ret == GNUNET_OK) + { + GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s", + dir_social, DIR_SEPARATOR, + "apps", DIR_SEPARATOR, + app_id, DIR_SEPARATOR, + ego_pub_hash_ascii.encoding, DIR_SEPARATOR, + place_pub_hash_ascii.encoding); + ret = GNUNET_DISK_directory_create_for_file (filename); + if (GNUNET_OK != ret + || 0 > GNUNET_DISK_fn_write (filename, "", 0, + GNUNET_DISK_PERM_USER_READ + | GNUNET_DISK_PERM_USER_WRITE)) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + } + GNUNET_free (filename); + } + return ret; +} + + +int +app_place_remove (const char *app_id, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key) +{ + struct GNUNET_HashCode place_pub_hash; + GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash); + + struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii; + memcpy (&place_pub_hash_ascii.encoding, + GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii)); + + char *app_place_filename = NULL; + GNUNET_asprintf (&app_place_filename, + "%s%c" "%s%/", + dir_social, DIR_SEPARATOR, + "apps", DIR_SEPARATOR, + app_id, DIR_SEPARATOR, + place_pub_hash_ascii.encoding); + + struct GNUNET_HashCode app_id_hash; + GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); + + struct GNUNET_CONTAINER_MultiHashMap * + app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); - GNUNET_DISK_directory_create_for_file (filename); - if (GNUNET_DISK_fn_write (filename, msg, ntohs (msg->size), - GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE) < 0) + if (NULL != app_places) + GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL); + + int ret = unlink (app_place_filename); + GNUNET_free (app_place_filename); + if (0 != ret) { GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error removing app place: unlink returned %d\n", errno); + return GNUNET_SYSERR; } - GNUNET_free (ego_pub_hash_str); - GNUNET_free (place_pub_hash_str); - GNUNET_free (filename); + return GNUNET_OK; } @@ -772,35 +971,34 @@ place_save (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_key, * Returned Host struct. * * @return #GNUNET_YES if the host entered the place just now, - * #GNUNET_NO if the place is already entered. + * #GNUNET_NO if the place is already entered, + * #GNUNET_SYSERR if place_pub_key was set + * but its private key was not found */ static int host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst) { int ret = GNUNET_NO; - struct GNUNET_CRYPTO_EddsaPublicKey place_pub; struct GNUNET_HashCode place_pub_hash; - - GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub); - GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash); - + GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key), + &place_pub_hash); struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash); + if (NULL == hst) { hst = GNUNET_new (struct Host); - hst->policy = ntohl (hreq->policy); - hst->priv_key = hreq->place_key; + hst->policy = hreq->policy; hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); struct Place *plc = &hst->plc; + place_init (plc); plc->is_host = GNUNET_YES; - plc->pub_key = place_pub; + plc->pub_key = hreq->place_pub_key; plc->pub_key_hash = place_pub_hash; - place_init (plc); GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy, + hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy, &psyc_master_started, &psyc_recv_join_request, &psyc_recv_message, NULL, hst); @@ -821,10 +1019,41 @@ static void client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg) { - const struct HostEnterRequest *hreq - = (const struct HostEnterRequest *) msg; - struct Place *plc; - struct Host *hst; + struct HostEnterRequest *hreq + = (struct HostEnterRequest *) GNUNET_copy_message (msg); + + uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq); + const char *app_id = NULL; + uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1], + app_id_size, 1, &app_id); + if (0 == offset || offset != app_id_size || app_id == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "offset = %u, app_id_size = %u, app_id = %s\n", + offset, app_id_size, app_id); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + struct Host *hst = NULL; + struct Place *plc = NULL; + int ret = GNUNET_OK; + + struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key; + memset (&empty_pub_key, 0, sizeof (empty_pub_key)); + + if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key))) + { // no public key set: create new private key & save the place + struct GNUNET_CRYPTO_EddsaPrivateKey * + place_key = GNUNET_CRYPTO_eddsa_key_create (); + hreq->place_key = *place_key; + GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key); + GNUNET_CRYPTO_eddsa_key_clear (place_key); + GNUNET_free (place_key); + + app_place_save (app_id, (const struct PlaceEnterRequest *) hreq); + } switch (host_enter (hreq, &hst)) { @@ -835,40 +1064,32 @@ client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client, case GNUNET_NO: { plc = &hst->plc; - - struct GNUNET_PSYC_CountersResultMessage res; - res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK); - res.header.size = htons (sizeof (res)); - res.result_code = htonl (GNUNET_OK); - res.max_message_id = GNUNET_htonll (plc->max_message_id); - - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, &res.header, - GNUNET_NO); + client_send_host_enter_ack (client, hst, GNUNET_OK); break; } case GNUNET_SYSERR: - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; + ret = GNUNET_SYSERR; } - struct GNUNET_CRYPTO_EddsaPublicKey place_pub; - GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub); + if (ret != GNUNET_SYSERR) + { - place_save (&hreq->host_key, &place_pub, msg); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%p Client connected as host to place %s.\n", + hst, GNUNET_h2s (&plc->pub_key_hash)); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Client connected as host to place %s.\n", - hst, GNUNET_h2s (&plc->pub_key_hash)); + struct ClientListItem *cli = GNUNET_new (struct ClientListItem); + cli->client = client; + GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); - struct ClientListItem *cli = GNUNET_new (struct ClientListItem); - cli->client = client; - GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); + struct Client *ctx = GNUNET_new (struct Client); + ctx->plc = plc; + GNUNET_SERVER_client_set_user_context (client, ctx); + } - struct Client *ctx = GNUNET_new (struct Client); - ctx->plc = plc; - GNUNET_SERVER_client_set_user_context (client, ctx); - GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key); + GNUNET_free (hreq); + GNUNET_SERVER_receive_done (client, ret); } @@ -881,7 +1102,8 @@ client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client, * Returned Guest struct. * * @return #GNUNET_YES if the guest entered the place just now, - * #GNUNET_NO if the place is already entered. + * #GNUNET_NO if the place is already entered, + * #GNUNET_SYSERR on error. */ static int guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) @@ -889,44 +1111,68 @@ guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) int ret = GNUNET_NO; uint16_t greq_size = ntohs (greq->header.size); - struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key; - struct GNUNET_HashCode place_pub_hash, gst_pub_key_hash; - GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &gst_pub_key); - GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash); - GNUNET_CRYPTO_hash (&greq->place_key, sizeof (greq->place_key), &place_pub_hash); + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key; + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); + struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); + + if (NULL == ego) + return GNUNET_SYSERR; + + struct GNUNET_HashCode place_pub_hash; + GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key), + &place_pub_hash); struct GNUNET_CONTAINER_MultiHashMap * plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash); struct Guest *gst = NULL; - struct Place *plc; if (NULL != plc_gst) - gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash); + gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash); if (NULL == gst || NULL == gst->slave) { gst = GNUNET_new (struct Guest); - gst->priv_key = greq->guest_key; - gst->pub_key = gst_pub_key; - gst->pub_key_hash = gst_pub_key_hash; gst->origin = greq->origin; gst->relay_count = ntohl (greq->relay_count); + uint16_t len; + uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); + const char *app_id = (const char *) &greq[1]; + const char *p = app_id; + + len = strnlen (app_id, remaining); + if (len == remaining) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + p += len + 1; + remaining -= len + 1; + const struct GNUNET_PeerIdentity *relays = NULL; uint16_t relay_size = gst->relay_count * sizeof (*relays); + if (remaining < relay_size) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } if (0 < relay_size) - relays = (const struct GNUNET_PeerIdentity *) &greq[1]; + relays = (const struct GNUNET_PeerIdentity *) p; + p += relay_size; + remaining -= relay_size; + struct GNUNET_PSYC_Message *join_msg = NULL; uint16_t join_msg_size = 0; - if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader) - <= greq_size) + if (sizeof (struct GNUNET_MessageHeader) <= remaining) { - join_msg = (struct GNUNET_PSYC_Message *) - (((char *) &greq[1]) + relay_size); + join_msg = (struct GNUNET_PSYC_Message *) p; join_msg_size = ntohs (join_msg->header.size); + p += join_msg_size; + remaining -= join_msg_size; } - if (sizeof (*greq) + relay_size + join_msg_size != greq_size) + if (0 != remaining) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u + %u + %u != %u\n", @@ -935,17 +1181,20 @@ guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) GNUNET_free (gst); return GNUNET_SYSERR; } - if (0 < gst->relay_count) + if (0 < relay_size) { gst->relays = GNUNET_malloc (relay_size); - memcpy (gst->relays, &greq[1], relay_size); + memcpy (gst->relays, relays, relay_size); } - plc = &gst->plc; + struct Place *plc = &gst->plc; + place_init (plc); plc->is_host = GNUNET_NO; - plc->pub_key = greq->place_key; + plc->pub_key = greq->place_pub_key; plc->pub_key_hash = place_pub_hash; - place_init (plc); + plc->ego_pub_key = ego_pub_key; + plc->ego_pub_hash = ego_pub_hash; + plc->ego_key = ego->key; if (NULL == plc_gst) { @@ -953,12 +1202,12 @@ guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } - (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, gst, + (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); gst->slave - = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key, + = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key, &gst->origin, gst->relay_count, gst->relays, &psyc_recv_message, NULL, &psyc_slave_connected, &psyc_recv_join_dcsn, gst, join_msg); @@ -981,6 +1230,18 @@ client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client, { const struct GuestEnterRequest * greq = (const struct GuestEnterRequest *) msg; + + uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); + const char *app_id = NULL; + uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1], + remaining, 1, &app_id); + if (0 == offset) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + struct Guest *gst = NULL; struct Place *plc = NULL; @@ -988,6 +1249,7 @@ client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client, { case GNUNET_YES: plc = &gst->plc; + app_place_save (app_id, (const struct PlaceEnterRequest *) greq); break; case GNUNET_NO: @@ -1000,28 +1262,21 @@ client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client, res.result_code = htonl (GNUNET_OK); res.max_message_id = GNUNET_htonll (plc->max_message_id); - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, &res.header, - GNUNET_NO); + client_send_msg (client, &res.header); if (NULL != gst->join_dcsn) - { - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, - &gst->join_dcsn->header, - GNUNET_NO); - } + client_send_msg (client, &gst->join_dcsn->header); + break; } case GNUNET_SYSERR: + GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - place_save (&greq->guest_key, &greq->place_key, msg); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p Client connected as guest to place %s.\n", - gst, GNUNET_h2s (&gst->plc.pub_key_hash)); + gst, GNUNET_h2s (&plc->pub_key_hash)); struct ClientListItem *cli = GNUNET_new (struct ClientListItem); cli->client = client; @@ -1034,16 +1289,159 @@ client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client, } +struct GuestEnterByNameClosure +{ + struct GNUNET_SERVER_Client *client; + char *app_id; + char *password; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + struct GNUNET_MessageHeader *join_msg; +}; + + +/** + * Result of a GNS name lookup for entering a place. + * + * @see GNUNET_SOCIAL_guest_enter_by_name + */ +static void +gns_result_guest_enter (void *cls, uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct GuestEnterByNameClosure *gcls = cls; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%p GNS result: %u records.\n", gcls->client, rd_count); + + const struct GNUNET_GNSRECORD_PlaceData * + rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data; + + if (0 == rd_count || rd->data_size < sizeof (*rec)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (gcls->client, GNUNET_SYSERR); + return; + } + + uint16_t relay_count = ntohl (rec->relay_count); + struct GNUNET_PeerIdentity *relays = NULL; + + if (0 < relay_count) + { + if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity)) + { + relays = (struct GNUNET_PeerIdentity *) &rec[1]; + } + else + { + relay_count = 0; + GNUNET_break_op (0); + } + } + + uint16_t app_id_size = strlen (gcls->app_id) + 1; + uint16_t relay_size = relay_count * sizeof (*relays); + uint16_t join_msg_size = 0; + if (NULL != gcls->join_msg) + join_msg_size = ntohs (gcls->join_msg->size); + uint16_t greq_size = sizeof (struct GuestEnterRequest) + + app_id_size + relay_size + join_msg_size; + struct GuestEnterRequest *greq = GNUNET_malloc (greq_size); + greq->header.size = htons (greq_size); + greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); + greq->ego_pub_key = gcls->ego_pub_key; + greq->place_pub_key = rec->place_pub_key; + greq->origin = rec->origin; + greq->relay_count = rec->relay_count; + + void *p = &greq[1]; + memcpy (p, gcls->app_id, app_id_size); + p += app_id_size; + memcpy (p, relays, relay_size); + p += relay_size; + memcpy (p, gcls->join_msg, join_msg_size); + + client_recv_guest_enter (NULL, gcls->client, &greq->header); + + GNUNET_free (gcls->app_id); + if (NULL != gcls->password) + GNUNET_free (gcls->password); + if (NULL != gcls->join_msg) + GNUNET_free (gcls->join_msg); + GNUNET_free (gcls); + GNUNET_free (greq); +} + + +/** + * Handle a connecting client entering a place as guest using a GNS address. + * + * Look up GNS address and generate a GuestEnterRequest from that. + */ +static void +client_recv_guest_enter_by_name (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + const struct GuestEnterByNameRequest * + greq = (const struct GuestEnterByNameRequest *) msg; + + struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls)); + gcls->client = client; + gcls->ego_pub_key = greq->ego_pub_key; + + const char *p = (const char *) &greq[1]; + const char *app_id = NULL, *password = NULL, *gns_name = NULL; + uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); + uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3, + &app_id, + &gns_name, + &password); + p += offset; + remaining -= offset; + + if (0 != offset && sizeof (*gcls->join_msg) <= remaining) + { + gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p); + remaining -= ntohs (gcls->join_msg->size); + } + + if (0 == offset || 0 != remaining) + { + if (NULL != gcls->join_msg) + GNUNET_free (gcls->join_msg); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + uint16_t app_id_size = strlen (app_id) + 1; + gcls->app_id = GNUNET_malloc (app_id_size); + memcpy (gcls->app_id, app_id, app_id_size); + + uint16_t password_size = strlen (password); + if (0 < password_size++) + { + gcls->password = GNUNET_malloc (password_size); + memcpy (gcls->password, password, password_size); + } + + GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key, + GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT, + NULL, gns_result_guest_enter, gcls); +} + + void -place_notify (struct GNUNET_MessageHeader *msg, - struct GNUNET_SERVER_Client *client) +app_notify_place (struct GNUNET_MessageHeader *msg, + struct GNUNET_SERVER_Client *client) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p Sending place notification of type %u to client.\n", client, ntohs (msg->type)); - uint16_t msg_size = ntohs (msg->size); - struct GNUNET_CRYPTO_EcdsaPublicKey place_pub; + uint16_t msg_size = ntohs (msg->size); + struct AppPlaceMessage amsg; + amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE); + amsg.header.size = htons (sizeof (amsg)); switch (ntohs (msg->type)) { @@ -1051,77 +1449,181 @@ place_notify (struct GNUNET_MessageHeader *msg, if (msg_size < sizeof (struct HostEnterRequest)) return; struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg; - GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &place_pub); + amsg.is_host = GNUNET_YES; + amsg.ego_pub_key = hreq->ego_pub_key; + amsg.place_pub_key = hreq->place_pub_key; break; case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: if (msg_size < sizeof (struct GuestEnterRequest)) return; struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg; - GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &place_pub); + amsg.is_host = GNUNET_NO; + amsg.ego_pub_key = greq->ego_pub_key; + amsg.place_pub_key = greq->place_pub_key; break; default: return; } - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, msg, - GNUNET_NO); + client_send_msg (client, &amsg.header); +} + + +void +app_notify_ego (struct Ego *ego, struct GNUNET_SERVER_Client *client) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%p Sending ego notification to client: %s\n", + client, ego->name); + + size_t name_size = strlen (ego->name) + 1; + struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size); + emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO); + emsg->header.size = htons (sizeof (*emsg) + name_size); + + GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key); + memcpy (&emsg[1], ego->name, name_size); + + client_send_msg (client, &emsg->header); + GNUNET_free (emsg); +} + + +int +app_place_entry (void *cls, const struct GNUNET_HashCode *key, void *value) +{ + struct GNUNET_MessageHeader * + msg = GNUNET_CONTAINER_multihashmap_get (places, key); + if (NULL != msg) + app_notify_place (msg, cls); + return GNUNET_YES; } int -map_entry_place (void *cls, const struct GNUNET_HashCode *key, void *value) +ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value) { - place_notify (value, cls); + app_notify_ego (value, cls); return GNUNET_YES; } /** - * Handle a connecting client listening for entered places. + * Handle application connection. */ static void -client_recv_place_listen (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *msg) +client_recv_app_connect (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) { - const struct PlaceListenRequest *req - = (const struct PlaceListenRequest *) msg; + const struct AppConnectRequest *creq + = (const struct AppConnectRequest *) msg; + + uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq); + const char *app_id = NULL; + uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1], + app_id_size, 1, &app_id); + if (0 == offset || offset != app_id_size) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub; - struct GNUNET_HashCode ego_pub_hash; + struct GNUNET_HashCode app_id_hash; + GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash); - GNUNET_CRYPTO_ecdsa_key_get_public (&req->ego_key, &ego_pub); - GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash); + GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client); struct GNUNET_CONTAINER_MultiHashMap * - ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, &ego_pub_hash); - if (NULL != ego_places) - GNUNET_CONTAINER_multihashmap_iterate (ego_places, map_entry_place, client); - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Client connected to listen for entered places of ego %s.\n", - NULL, GNUNET_h2s (&ego_pub_hash)); + app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); + if (NULL != app_places) + GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry, client); struct ClientListItem *cli = GNUNET_new (struct ClientListItem); cli->client = client; - struct PlaceListener *pl = GNUNET_CONTAINER_multihashmap_get (place_listeners, - &ego_pub_hash); - if (NULL == pl) { - pl = GNUNET_malloc (sizeof (*pl)); - (void) GNUNET_CONTAINER_multihashmap_put (place_listeners, &ego_pub_hash, pl, + struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps, + &app_id_hash); + if (NULL == app) { + app = GNUNET_malloc (sizeof (*app)); + (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } - GNUNET_CONTAINER_DLL_insert (pl->clients_head, pl->clients_tail, cli); + GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%p Application %s connected.\n", app, app_id); struct Client *ctx = GNUNET_new (struct Client); - ctx->ego_key = req->ego_key; + ctx->app_id = GNUNET_malloc (app_id_size); + memcpy (ctx->app_id, app_id, app_id_size); + GNUNET_SERVER_client_set_user_context (client, ctx); GNUNET_SERVER_receive_done (client, GNUNET_OK); } +/** + * Handle application detach request. + */ +static void +client_recv_app_detach (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + struct Client * + ctx = GNUNET_SERVER_client_get_user_context (client, struct Client); + GNUNET_assert (NULL != ctx); + + const struct AppDetachRequest *req + = (const struct AppDetachRequest *) msg; + + int ret = app_place_remove (ctx->app_id, &req->place_pub_key); + client_send_result (client, req->op_id, ret, NULL, 0); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle application detach request. + */ +static void +client_recv_place_leave (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + struct Client * + ctx = GNUNET_SERVER_client_get_user_context (client, struct Client); + GNUNET_assert (NULL != ctx); + struct Place *plc = ctx->plc; + + /* Disconnect all clients connected to the place */ + /* FIXME: disconnect from the network, but keep local connection for history access */ + struct ClientListItem *cli = plc->clients_head, *next; + while (NULL != cli) + { + GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli); + GNUNET_SERVER_client_disconnect (cli->client); + next = cli->next; + GNUNET_free (cli); + cli = next; + } + + if (GNUNET_YES != plc->is_disconnected) + { + plc->is_disconnected = GNUNET_YES; + if (NULL != plc->tmit_msgs_head) + { /* Send pending messages to PSYC before cleanup. */ + psyc_transmit_message (plc); + } + else + { + cleanup_place (plc); + } + } +} + + struct JoinDecisionClosure { int32_t is_admitted; @@ -1198,9 +1700,7 @@ send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client) struct GNUNET_MessageHeader res; res.size = htons (sizeof (res)); res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK); - - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO); + client_send_msg (client, &res); } @@ -1872,7 +2372,7 @@ psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags, memcpy (&res[1], msg, size); /** @todo FIXME: send only to requesting client */ - client_send_msg (plc, &res->header); + place_send_msg (plc, &res->header); } @@ -1977,7 +2477,7 @@ psyc_recv_state_var (void *cls, memcpy (&res[1], mod, size); /** @todo FIXME: send only to requesting client */ - client_send_msg (plc, &res->header); + place_send_msg (plc, &res->header); } @@ -2059,6 +2559,130 @@ client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client, } +static void +namestore_recv_records_store_result (void *cls, int32_t result, + const char *err_msg) +{ + struct OperationClosure *ocls = cls; + client_send_result (ocls->client, ocls->op_id, result, err_msg, + (NULL != err_msg) ? strlen (err_msg) : 0); + GNUNET_free (ocls); +} + + +/** + * Handle request to add PLACE record to GNS zone. + */ +static void +client_recv_zone_add_place (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + const struct ZoneAddPlaceRequest *preq + = (const struct ZoneAddPlaceRequest *) msg; + + uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq); + const char *p = (const char *) &preq[1]; + const char *name = NULL, *password = NULL; + uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2, + &name, &password); + remaining -= offset; + p += offset; + const struct GNUNET_PeerIdentity * + relays = (const struct GNUNET_PeerIdentity *) p; + uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays); + + if (0 == offset || remaining != relay_size) + { + GNUNET_break (0); + client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct GNUNET_GNSRECORD_Data rd = { }; + rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE; + rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd.expiration_time = GNUNET_ntohll (preq->expiration_time); + + struct GNUNET_GNSRECORD_PlaceData * + rec = GNUNET_malloc (sizeof (*rec) + relay_size); + rec->place_pub_key = preq->place_pub_key; + rec->origin = this_peer; + rec->relay_count = preq->relay_count; + memcpy (&rec[1], relays, relay_size); + + rd.data = rec; + rd.data_size = sizeof (*rec) + relay_size; + + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash); + struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); + if (NULL == ego) + { + client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); + } + else + { + struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls)); + ocls->client = client; + ocls->op_id = preq->op_id; + GNUNET_NAMESTORE_records_store (namestore, &ego->key, + name, 1, &rd, + namestore_recv_records_store_result, ocls); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle request to add PLACE record to GNS zone. + */ +static void +client_recv_zone_add_nym (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + const struct ZoneAddNymRequest *nreq + = (const struct ZoneAddNymRequest *) msg; + + uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq); + const char *name = NULL; + uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1], + name_size, 1, &name); + if (0 == offset || offset != name_size) + { + GNUNET_break (0); + client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct GNUNET_GNSRECORD_Data rd = { }; + rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; + rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd.expiration_time = GNUNET_ntohll (nreq->expiration_time); + rd.data = &nreq->nym_pub_key; + rd.data_size = sizeof (nreq->nym_pub_key); + + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash); + struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); + if (NULL == ego) + { + client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); + } + else + { + struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls)); + ocls->client = client; + ocls->op_id = nreq->op_id; + GNUNET_NAMESTORE_records_store (namestore, &ego->key, + name, 1, &rd, + namestore_recv_records_store_result, ocls); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + static const struct GNUNET_SERVER_MessageHandler handlers[] = { { &client_recv_host_enter, NULL, GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 }, @@ -2066,6 +2690,9 @@ static const struct GNUNET_SERVER_MessageHandler handlers[] = { { &client_recv_guest_enter, NULL, GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 }, + { &client_recv_guest_enter_by_name, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, 0 }, + { &client_recv_join_decision, NULL, GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 }, @@ -2081,50 +2708,79 @@ static const struct GNUNET_SERVER_MessageHandler handlers[] = { { &client_recv_state_get, NULL, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 }, - { &client_recv_place_listen, NULL, - GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN, 0 }, + { &client_recv_zone_add_place, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, 0 }, + + { &client_recv_zone_add_nym, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, 0 }, + + { &client_recv_app_connect, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, 0 }, + + { &client_recv_app_detach, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, 0 }, + + { &client_recv_place_leave, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, 0 }, { NULL, NULL, 0, 0 } }; +const char * +path_basename (const char *path) +{ + const char *basename = strrchr (path, DIR_SEPARATOR); + if (NULL != basename) + basename++; + + if (NULL == basename || '\0' == basename) + return NULL; + + return basename; +} + + +struct PlaceLoadClosure +{ + const char *app_id; + const char *ego_pub_hash_str; +}; + + +/** Load a place file */ int file_place_load (void *cls, const char *filename) { - uint64_t fsize = 0; + char *app_id = cls; + uint64_t file_size = 0; if (GNUNET_OK != - GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES, GNUNET_YES) - || fsize < sizeof (struct HostEnterRequest)) + GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES) + || file_size < sizeof (struct HostEnterRequest)) return GNUNET_OK; - struct GNUNET_MessageHeader *msg = GNUNET_malloc (fsize); - ssize_t rsize = GNUNET_DISK_fn_read (filename, msg, fsize); - if (rsize < 0 || (size_t) rsize < sizeof (*msg)) + struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size); + ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size); + if (read_size < 0 || read_size < sizeof (*ereq)) return GNUNET_OK; - uint16_t msg_size = ntohs (msg->size); - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub; - struct GNUNET_CRYPTO_EddsaPublicKey place_pub; + uint16_t ereq_size = ntohs (ereq->header.size); + if (read_size != ereq_size) + return GNUNET_OK; - switch (ntohs (msg->type)) + switch (ntohs (ereq->header.type)) { case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER: - if (msg_size < sizeof (struct HostEnterRequest)) + if (ereq_size < sizeof (struct HostEnterRequest)) return GNUNET_OK; - struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg; - GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &ego_pub); - GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub); - + struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq; host_enter (hreq, NULL); break; case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: - if (msg_size < sizeof (struct GuestEnterRequest)) + if (ereq_size < sizeof (struct GuestEnterRequest)) return GNUNET_OK; - struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg; - GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &ego_pub); - place_pub = greq->place_key; - + struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq; guest_enter (greq, NULL); break; @@ -2132,40 +2788,135 @@ file_place_load (void *cls, const char *filename) return GNUNET_OK; } - struct GNUNET_HashCode ego_pub_hash, place_pub_hash; - GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash); - GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash); + app_place_add (app_id, ereq); + return GNUNET_OK; +} + + +/** Load an ego place file */ +int +file_ego_place_load (void *cls, const char *place_filename) +{ + struct PlaceLoadClosure *plcls = cls; - place_add (&ego_pub_hash, &place_pub_hash, msg); + const char *place_pub_hash_str = path_basename (place_filename); + if (NULL == place_pub_hash_str) + { + GNUNET_break (0); + return GNUNET_OK; + } + + char *filename = NULL; + GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", + dir_social, DIR_SEPARATOR, + "places", DIR_SEPARATOR, + plcls->ego_pub_hash_str, DIR_SEPARATOR, + place_pub_hash_str); + + struct PlaceEnterRequest ereq[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + + int read_size = GNUNET_DISK_fn_read (filename, &ereq, + GNUNET_SERVER_MAX_MESSAGE_SIZE); + GNUNET_free (filename); + + if (read_size < (ssize_t) sizeof (ereq)) + return GNUNET_OK; + + app_place_add (plcls->app_id, ereq); return GNUNET_OK; } +/** + * Read @e place_pub_hash_str entries in @a dir_ego + * + * @param dir_ego + * Data directory of an application ego. + * e.g. ~/.local/share/gnunet/social/apps/$app_id/$ego_pub_hash_str/ + */ +int +scan_app_ego_dir (void *cls, const char *dir_ego) +{ + struct PlaceLoadClosure *plcls = cls; + plcls->ego_pub_hash_str = path_basename (dir_ego); + + if (NULL != plcls->ego_pub_hash_str) + GNUNET_DISK_directory_scan (dir_ego, file_ego_place_load, plcls); + + return GNUNET_OK; +} + +/** + * Read @e ego_pub_hash_str entries in @a dir_app + * + * @param dir_app + * Data directory of an application. + * e.g. ~/.local/share/gnunet/social/apps/$app_id/ + */ int -load_places_of_ego (void *cls, const char *dir_ego) +scan_app_dir (void *cls, const char *dir_app) { - if (GNUNET_YES != GNUNET_DISK_directory_test (dir_ego, GNUNET_YES)) + if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES)) return GNUNET_OK; - GNUNET_DISK_directory_scan (dir_ego, file_place_load, NULL); + struct PlaceLoadClosure plcls; + plcls.app_id = path_basename (dir_app); + + if (NULL != plcls.app_id) + GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls); + return GNUNET_OK; } -void -load_places () +static void +identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego, + void **ctx, const char *name) { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "PLACES_DIR", - &dir_places)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "social", "PLACES_DIR"); - GNUNET_break (0); + if (NULL == id_ego) // end of initial list of egos return; + + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key); + + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); + + struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); + if (NULL != ego) + { + GNUNET_free (ego->name); + if (NULL == name) // deleted + { + GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego); + GNUNET_free (ego); + ego = NULL; + } + } + else + { + ego = GNUNET_malloc (sizeof (*ego)); } + if (NULL != ego) + { + ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego)); + size_t name_size = strlen (name) + 1; + ego->name = GNUNET_malloc (name_size); + memcpy (ego->name, name, name_size); - places_entered = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); - GNUNET_DISK_directory_scan (dir_places, load_places_of_ego, NULL); + GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + } +} + + +/** + * Connected to core service. + */ +static void +core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity) +{ + this_peer = *my_identity; } @@ -2181,12 +2932,38 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; - stats = GNUNET_STATISTICS_create ("social", cfg); + hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - place_listeners = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - load_places (); + + egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); + apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); + + core = GNUNET_CORE_connect (cfg, NULL, core_connected, NULL, NULL, + NULL, GNUNET_NO, NULL, GNUNET_NO, NULL); + id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL); + gns = GNUNET_GNS_connect (cfg); + namestore = GNUNET_NAMESTORE_connect (cfg); + stats = GNUNET_STATISTICS_create ("social", cfg); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "SOCIAL_DATA_DIR", + &dir_social)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "social", "SOCIAL_DATA_DIR"); + GNUNET_break (0); + return; + } + GNUNET_asprintf (&dir_places, "%s%c%s", + dir_social, DIR_SEPARATOR, "places"); + GNUNET_asprintf (&dir_apps, "%s%c%s", + dir_social, DIR_SEPARATOR, "apps"); + + GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL); nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SERVER_add_handlers (server, handlers); diff --git a/src/social/social.h b/src/social/social.h index 6dfd556129..651338c510 100644 --- a/src/social/social.h +++ b/src/social/social.h @@ -49,6 +49,37 @@ GNUNET_NETWORK_STRUCT_BEGIN /**** library -> service ****/ +struct AppConnectRequest +{ + /** + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT + */ + struct GNUNET_MessageHeader header; + + /* Followed by char *app_id */ +}; + + +struct AppDetachRequest +{ + /** + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH + */ + struct GNUNET_MessageHeader header; + + /** + * Public key of place. + */ + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; + + /** + * Operation ID. + */ + uint64_t op_id GNUNET_PACKED; + +}; + + struct HostEnterRequest { /** @@ -58,46 +89,179 @@ struct HostEnterRequest uint32_t policy GNUNET_PACKED; - struct GNUNET_CRYPTO_EcdsaPrivateKey host_key; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; struct GNUNET_CRYPTO_EddsaPrivateKey place_key; + + /* Followed by char *app_id */ }; struct GuestEnterRequest { /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ADDR + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER */ struct GNUNET_MessageHeader header; uint32_t relay_count GNUNET_PACKED; - struct GNUNET_CRYPTO_EcdsaPrivateKey guest_key; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - struct GNUNET_CRYPTO_EddsaPublicKey place_key; + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; struct GNUNET_PeerIdentity origin; + /* Followed by char *app_id */ /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ + /* Followed by struct GNUNET_MessageHeader *join_msg */ +}; + - /* Followed by struct GNUNET_MessageHeader join_msg */ +/** Compatible parts of HostEnterRequest and GuestEnterRequest */ +struct PlaceEnterRequest +{ + struct GNUNET_MessageHeader header; + + uint32_t reserved GNUNET_PACKED; + + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; }; -struct PlaceListenRequest +struct EgoPlacePublicKey +{ + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; +}; + + +struct GuestEnterByNameRequest { /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME */ struct GNUNET_MessageHeader header; - struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + /* Followed by char *app_id */ + /* Followed by char *gns_name */ + /* Followed by char *password */ + /* Followed by struct GNUNET_MessageHeader *join_msg */ }; +struct ZoneAddPlaceRequest +{ + struct GNUNET_MessageHeader header; + + uint32_t relay_count GNUNET_PACKED; + + /** + * Operation ID. + */ + uint64_t op_id; + + /** + * Expiration time: absolute value in us. + */ + uint64_t expiration_time; + + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; + + struct GNUNET_PeerIdentity origin; + + /* Followed by const char *name */ + /* Followed by const char *password */ + /* Followed by struct GNUNET_PeerIdentity *relays[relay_count] */ +}; + + +struct ZoneAddNymRequest +{ + struct GNUNET_MessageHeader header; + + /** + * Operation ID. + */ + uint64_t op_id; + + /** + * Expiration time: absolute value in us. + */ + uint64_t expiration_time; + + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; + + /* Followed by const char *name */ +}; + /**** service -> library ****/ + +struct AppEgoMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO + */ + struct GNUNET_MessageHeader header; + + /** + * Public key of ego. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + /* Followed by char *name */ +}; + + +struct AppPlaceMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE + */ + struct GNUNET_MessageHeader header; + + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; + + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; + + uint8_t is_host; +}; + + +struct HostEnterAck { + /** + * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * Status code for the operation. + */ + uint32_t result_code GNUNET_PACKED; + + /** + * Last message ID sent to the channel. + */ + uint64_t max_message_id GNUNET_PACKED; + + /** + * Public key of the place. + */ + struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; +}; + + #if REMOVE struct NymEnterRequest { @@ -105,6 +269,7 @@ struct NymEnterRequest * Type: GNUNET_MESSAGE_TYPE_SOCIAL_NYM_ENTER */ struct GNUNET_MessageHeader header; + /** * Public key of the joining slave. */ diff --git a/src/social/social_api.c b/src/social/social_api.c index 9a2f99ae88..6c85ba2948 100644 --- a/src/social/social_api.c +++ b/src/social/social_api.c @@ -30,10 +30,6 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_env_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_identity_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_gns_service.h" #include "gnunet_psyc_service.h" #include "gnunet_psyc_util_lib.h" #include "gnunet_social_service.h" @@ -41,11 +37,15 @@ #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__) - -static struct GNUNET_CORE_Handle *core; -static struct GNUNET_GNS_Handle *gns; -static struct GNUNET_NAMESTORE_Handle *namestore; -static struct GNUNET_PeerIdentity this_peer; +/** + * Handle for an ego. + */ +struct GNUNET_SOCIAL_Ego +{ + struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; + struct GNUNET_HashCode pub_key_hash; + char *name; +}; /** @@ -59,6 +59,76 @@ struct GNUNET_SOCIAL_Nym /** + * Handle for an application. + */ +struct GNUNET_SOCIAL_App +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Client connection to the service. + */ + struct GNUNET_CLIENT_MANAGER_Connection *client; + + /** + * Message to send on reconnect. + */ + struct GNUNET_MessageHeader *connect_msg; + + /** + * Function called after disconnected from the service. + */ + GNUNET_ContinuationCallback disconnect_cb; + + /** + * Closure for @a disconnect_cb. + */ + void *disconnect_cls; + + /** + * Application ID. + */ + char *id; + + /** + * Hash map of all egos. + * pub_key_hash -> struct GNUNET_SOCIAL_Ego * + */ + struct GNUNET_CONTAINER_MultiHashMap *egos; + + GNUNET_SOCIAL_AppEgoCallback ego_cb; + GNUNET_SOCIAL_AppHostPlaceCallback host_cb; + GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb; + void *cb_cls; + + /** + * Is this place in the process of disconnecting from the service? + * #GNUNET_YES or #GNUNET_NO + */ + uint8_t is_disconnecting; +}; + + +struct GNUNET_SOCIAL_HostConnection +{ + struct GNUNET_SOCIAL_App *app; + + struct AppPlaceMessage plc_msg; +}; + + +struct GNUNET_SOCIAL_GuestConnection +{ + struct GNUNET_SOCIAL_App *app; + + struct AppPlaceMessage plc_msg; +}; + + +/** * Handle for a place where social interactions happen. */ struct GNUNET_SOCIAL_Place @@ -109,9 +179,9 @@ struct GNUNET_SOCIAL_Place struct GNUNET_CRYPTO_EddsaPublicKey pub_key; /** - * Private key of the ego. + * Public key of the ego. */ - struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; /** * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)? @@ -133,8 +203,6 @@ struct GNUNET_SOCIAL_Host { struct GNUNET_SOCIAL_Place plc; - struct GNUNET_CRYPTO_EddsaPrivateKey place_key; - /** * Receipt handle. */ @@ -190,19 +258,6 @@ struct GNUNET_SOCIAL_Guest /** - * Handle for place notifications. - */ -struct GNUNET_SOCIAL_PlaceListenHandle -{ - struct GNUNET_SOCIAL_Place plc; - - GNUNET_SOCIAL_PlaceNotifyHostCallback notify_host; - GNUNET_SOCIAL_PlaceNotifyGuestCallback notify_guest; - void *notify_cls; -}; - - -/** * Hash map of all nyms. * pub_key_hash -> struct GNUNET_SOCIAL_Nym * */ @@ -417,6 +472,22 @@ struct GNUNET_SOCIAL_LookHandle }; +struct ZoneAddPlaceHandle +{ + struct ZoneAddPlaceRequest *req; + GNUNET_ResultCallback result_cb; + void *result_cls; +}; + + +struct ZoneAddNymHandle +{ + struct ZoneAddNymRequest *req; + GNUNET_ResultCallback result_cb; + void *result_cls; +}; + + /*** NYM ***/ static struct GNUNET_SOCIAL_Nym * @@ -1012,6 +1083,31 @@ GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer) GNUNET_free (slicer); } +/*** CLIENT ***/ + + +static void +app_send_connect_msg (struct GNUNET_SOCIAL_App *app) +{ + uint16_t cmsg_size = ntohs (app->connect_msg->size); + struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size); + memcpy (cmsg, app->connect_msg, cmsg_size); + GNUNET_CLIENT_MANAGER_transmit_now (app->client, cmsg); +} + + +static void +app_recv_disconnect (void *cls, + struct GNUNET_CLIENT_MANAGER_Connection *client, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_SOCIAL_App * + app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app)); + + GNUNET_CLIENT_MANAGER_reconnect (client); + app_send_connect_msg (app); +} + /*** PLACE ***/ @@ -1066,6 +1162,32 @@ place_recv_result (void *cls, static void +app_recv_result (void *cls, + struct GNUNET_CLIENT_MANAGER_Connection *client, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_SOCIAL_App * + app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app)); + + const struct GNUNET_OperationResultMessage * + res = (const struct GNUNET_OperationResultMessage *) msg; + + uint16_t size = ntohs (msg->size); + if (size < sizeof (*res)) + { /* Error, message too small. */ + GNUNET_break (0); + return; + } + + uint16_t data_size = size - sizeof (*res); + const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; + GNUNET_CLIENT_MANAGER_op_result (app->client, GNUNET_ntohll (res->op_id), + GNUNET_ntohll (res->result_code), + data, data_size); +} + + +static void op_recv_history_result (void *cls, int64_t result, const void *err_msg, uint16_t err_msg_size) { @@ -1261,11 +1383,13 @@ host_recv_enter_ack (void *cls, hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (struct GNUNET_SOCIAL_Place)); - struct GNUNET_PSYC_CountersResultMessage * - cres = (struct GNUNET_PSYC_CountersResultMessage *) msg; - int32_t result = ntohl (cres->result_code); + struct HostEnterAck *hack = (struct HostEnterAck *) msg; + hst->plc.pub_key = hack->place_pub_key; + + int32_t result = ntohl (hack->result_code); if (NULL != hst->enter_cb) - hst->enter_cb (hst->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); + hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key, + GNUNET_ntohll (hack->max_message_id)); } @@ -1364,52 +1488,85 @@ guest_recv_join_decision (void *cls, static void -notify_recv_place_host (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +app_recv_ego (void *cls, + struct GNUNET_CLIENT_MANAGER_Connection *client, + const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SOCIAL_PlaceListenHandle * - pl = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*pl)); - if (NULL == pl->notify_host) - return; + struct GNUNET_SOCIAL_App * + app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app)); - struct HostEnterRequest * - hreq = (struct HostEnterRequest *) msg; + struct AppEgoMessage * + emsg = (struct AppEgoMessage *) msg; - pl->notify_host (pl->notify_cls, &hreq->place_key, ntohl (hreq->policy)); + uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg); + + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key), + &ego_pub_hash); + + struct GNUNET_SOCIAL_Ego * + ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); + if (NULL == ego) + { + ego = GNUNET_malloc (sizeof (*ego)); + ego->pub_key = emsg->ego_pub_key; + ego->name = GNUNET_malloc (name_size); + memcpy (ego->name, &emsg[1], name_size); + } + else + { + ego->name = GNUNET_realloc (ego->name, name_size); + memcpy (ego->name, &emsg[1], name_size); + } + + GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + if (NULL != app->ego_cb) + app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name); } static void -notify_recv_place_guest (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +app_recv_place (void *cls, + struct GNUNET_CLIENT_MANAGER_Connection *client, + const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SOCIAL_PlaceListenHandle * - pl = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*pl)); - if (NULL == pl->notify_guest) - return; + struct GNUNET_SOCIAL_App * + app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app)); - struct GuestEnterRequest * - greq = (struct GuestEnterRequest *) msg; - uint16_t greq_size = ntohs (greq->header.size); + struct AppPlaceMessage * + pmsg = (struct AppPlaceMessage *) msg; - const struct GNUNET_PeerIdentity *relays = NULL; - uint16_t relay_count = ntohs (greq->relay_count); - uint16_t relay_size = relay_count * sizeof (*relays); - if (0 < relay_size) - relays = (const struct GNUNET_PeerIdentity *) &greq[1]; - struct GNUNET_PSYC_Message *join_msg = NULL; + if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb) + || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb)) + return; - if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader) - <= greq_size) + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key), + &ego_pub_hash); + struct GNUNET_SOCIAL_Ego * + ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); + if (NULL == ego) { - join_msg = (struct GNUNET_PSYC_Message *) - (((char *) &greq[1]) + relay_size); + GNUNET_break (0); + return; } - pl->notify_guest (pl->notify_cls, &greq->place_key, &greq->origin, - relay_count, relays, join_msg); + if (GNUNET_YES == pmsg->is_host) + { + struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn)); + hconn->app = app; + hconn->plc_msg = *pmsg; + app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key); + } + else + { + struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn)); + gconn->app = app; + gconn->plc_msg = *pmsg; + app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key); + } } @@ -1417,7 +1574,7 @@ static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] = { { host_recv_enter_ack, NULL, GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK, - sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO }, + sizeof (struct HostEnterAck), GNUNET_NO }, { host_recv_enter_request, NULL, GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, @@ -1490,15 +1647,21 @@ static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] = -static struct GNUNET_CLIENT_MANAGER_MessageHandler notify_handlers[] = +static struct GNUNET_CLIENT_MANAGER_MessageHandler app_handlers[] = { - { notify_recv_place_host, NULL, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, - sizeof (struct HostEnterRequest), GNUNET_NO }, + { app_recv_ego, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO, + sizeof (struct AppEgoMessage), GNUNET_YES }, + + { app_recv_place, NULL, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE, + sizeof (struct AppPlaceMessage), GNUNET_NO }, - { notify_recv_place_guest, NULL, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, - sizeof (struct GuestEnterRequest), GNUNET_YES }, + { app_recv_result, NULL, + GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, + sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, + + { app_recv_disconnect, NULL, 0, 0, GNUNET_NO }, { NULL, NULL, 0, 0, GNUNET_NO } }; @@ -1515,22 +1678,6 @@ place_cleanup (struct GNUNET_SOCIAL_Place *plc) GNUNET_free (plc->connect_msg); if (NULL != plc->disconnect_cb) plc->disconnect_cb (plc->disconnect_cls); - - if (NULL != core) - { - GNUNET_CORE_disconnect (core); - core = NULL; - } - if (NULL != namestore) - { - GNUNET_NAMESTORE_disconnect (namestore); - namestore = NULL; - } - if (NULL != gns) - { - GNUNET_GNS_disconnect (gns); - gns = NULL; - } } @@ -1539,8 +1686,16 @@ host_cleanup (void *cls) { struct GNUNET_SOCIAL_Host *hst = cls; place_cleanup (&hst->plc); - GNUNET_PSYC_receive_destroy (hst->recv); - GNUNET_SOCIAL_slicer_destroy (hst->slicer); + if (NULL != hst->recv) + { + GNUNET_PSYC_receive_destroy (hst->recv); + hst->recv = NULL; + } + if (NULL != hst->slicer) + { + GNUNET_SOCIAL_slicer_destroy (hst->slicer); + hst->slicer = NULL; + } GNUNET_free (hst); } @@ -1568,11 +1723,13 @@ guest_cleanup (void *cls) * Identity of the host. * @param place_key * Private-public key pair of the place. - * NULL for ephemeral places. + * NULL to generate a key. * @param policy * Policy specifying entry and history restrictions for the place. * @param slicer * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. * @param answer_door_cb * Function to handle new nyms that want to enter. * @param farewell_cb @@ -1583,9 +1740,8 @@ guest_cleanup (void *cls) * @return Handle for the host. */ struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key, +GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, enum GNUNET_PSYC_Policy policy, struct GNUNET_SOCIAL_Slicer *slicer, GNUNET_SOCIAL_HostEnterCallback enter_cb, @@ -1595,35 +1751,17 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, { struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); struct GNUNET_SOCIAL_Place *plc = &hst->plc; - struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req)); - - if (NULL != place_key) - { - hst->place_key = *place_key; - } - else - { - struct GNUNET_CRYPTO_EddsaPrivateKey * - ephemeral_key = GNUNET_CRYPTO_eddsa_key_create (); - hst->place_key = *ephemeral_key; - GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key); - GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key); - GNUNET_free (ephemeral_key); - } - plc->cfg = cfg; + plc->cfg = app->cfg; plc->is_host = GNUNET_YES; plc->slicer = slicer; - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - GNUNET_CRYPTO_eddsa_key_get_public (place_key, &plc->pub_key); - hst->enter_cb = enter_cb; hst->answer_door_cb = answer_door_cb; hst->farewell_cb = farewell_cb; hst->cb_cls = cls; - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers); + plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", host_handlers); GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc)); plc->tmit = GNUNET_PSYC_transmit_create (plc->client); @@ -1636,13 +1774,15 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, NULL, host_recv_notice_place_leave_eom, hst); hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer); - req->header.size = htons (sizeof (*req)); - req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); - req->policy = policy; - req->place_key = hst->place_key; - req->host_key = plc->ego_key; + uint16_t app_id_size = strlen (app->id) + 1; + struct HostEnterRequest *hreq = GNUNET_malloc (sizeof (*hreq) + app_id_size); + hreq->header.size = htons (sizeof (*hreq) + app_id_size); + hreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); + hreq->policy = policy; + hreq->ego_pub_key = ego->pub_key; + memcpy (&hreq[1], app->id, app_id_size); - plc->connect_msg = (struct GNUNET_MessageHeader *) req; + plc->connect_msg = &hreq->header; place_send_connect_msg (plc); return hst; @@ -1650,22 +1790,15 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, /** - * Enter a place as host. + * Reconnect to an already entered place as host. * - * A place is created upon first entering, and it is active until permanently - * left using GNUNET_SOCIAL_host_leave(). - * - * @param cfg - * Configuration to contact the social service. - * @param ego - * Identity of the host. - * @param gns_name - * GNS name in the zone of the @a ego that contains the - * public key of the place in a PLACE record. - * @param policy - * Policy specifying entry and history restrictions for the place. + * @param hconn + * Host connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() * @param slicer * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. * @param answer_door_cb * Function to handle new nyms that want to enter. * @param farewell_cb @@ -1676,26 +1809,54 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, * @return Handle for the host. */ struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_IDENTITY_Ego *ego, - const char *gns_name, - enum GNUNET_PSYC_Policy policy, - struct GNUNET_SOCIAL_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls) -{ - struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {}; - - /* FIXME: - * 1. get public key by looking up PLACE entry under gns_name - * in the zone of the ego. - * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH - */ +GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, + struct GNUNET_SOCIAL_Slicer *slicer, + GNUNET_SOCIAL_HostEnterCallback enter_cb, + GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, + GNUNET_SOCIAL_FarewellCallback farewell_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); + struct GNUNET_SOCIAL_Place *plc = &hst->plc; + + size_t app_id_size = strlen (hconn->app->id) + 1; + struct HostEnterRequest *hreq = GNUNET_malloc (sizeof (*hreq) + app_id_size); + + hst->enter_cb = enter_cb; + hst->answer_door_cb = answer_door_cb; + hst->farewell_cb = farewell_cb; + hst->cb_cls = cls; + + plc->cfg = hconn->app->cfg; + plc->is_host = GNUNET_YES; + plc->slicer = slicer; + plc->pub_key = hconn->plc_msg.place_pub_key; + plc->ego_pub_key = hconn->plc_msg.ego_pub_key; + + plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", host_handlers); + GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc)); + + plc->tmit = GNUNET_PSYC_transmit_create (plc->client); + plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); + + hst->slicer = GNUNET_SOCIAL_slicer_create (); + GNUNET_SOCIAL_slicer_method_add (hst->slicer, "_notice_place_leave", + host_recv_notice_place_leave_method, + host_recv_notice_place_leave_modifier, + NULL, host_recv_notice_place_leave_eom, hst); + hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer); + + hreq->header.size = htons (sizeof (*hreq) + app_id_size); + hreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); + hreq->place_pub_key = hconn->plc_msg.place_pub_key; + hreq->ego_pub_key = hconn->plc_msg.ego_pub_key; + memcpy (&hreq[1], hconn->app->id, app_id_size); - return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer, - enter_cb, answer_door_cb, farewell_cb, cls); + plc->connect_msg = &hreq->header; + place_send_connect_msg (plc); + + GNUNET_free (hconn); + return hst; } @@ -1759,12 +1920,16 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, * Host of the place. * @param nym * Handle for the entity to be ejected. + * @param env + * Environment for the message or NULL. */ void GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst, - const struct GNUNET_SOCIAL_Nym *nym) + const struct GNUNET_SOCIAL_Nym *nym, + struct GNUNET_ENV_Environment *env) { - struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create (); + if (NULL == env) + env = GNUNET_ENV_environment_create (); GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET, "_nym", &nym->pub_key, sizeof (nym->pub_key)); GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL, @@ -1773,121 +1938,79 @@ GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst, /** - * Get the public key of a @a nym. + * Get the public key of @a ego. * - * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name(). - * - * @param nym - * Pseudonym to map to a cryptographic identifier. + * @param ego + * Ego. * - * @return Public key of nym. + * @return Public key of ego. */ const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym) +GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego) { - return &nym->pub_key; + return &ego->pub_key; } /** - * Get the hash of the public key of a @a nym. + * Get the hash of the public key of @a ego. * - * @param nym - * Pseudonym to map to a cryptographic identifier. + * @param ego + * Ego. * - * @return Hash of the public key of nym. + * @return Hash of the public key of @a ego. */ const struct GNUNET_HashCode * -GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym) +GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego) { - return &nym->pub_key_hash; + return &ego->pub_key_hash; } /** - * Obtain the private-public key pair of the hosted place. - * - * The public part is suitable for storing in GNS within a PLACE record, - * along with peer IDs to join at. + * Get the name of @a ego. * - * @param host - * Host of the place. + * @param ego + * Ego. * - * @return Private-public key pair of the hosted place. + * @return Public key of @a ego. */ -const struct GNUNET_CRYPTO_EddsaPrivateKey * -GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst) +const char * +GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego) { - return &hst->place_key; + return ego->name; } /** - * Connected to core service. + * Get the public key of @a nym. + * + * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). + * + * @param nym + * Pseudonym. + * + * @return Public key of @a nym. */ -static void -core_connected_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity) +const struct GNUNET_CRYPTO_EcdsaPublicKey * +GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym) { - this_peer = *my_identity; - // FIXME + return &nym->pub_key; } /** - * Advertise the place in the GNS zone of the @e ego of the @a host. + * Get the hash of the public key of @a nym. * - * @param hst - * Host of the place. - * @param name - * The name for the PLACE record to put in the zone. - * @param peer_count - * Number of elements in the @a peers array. - * @param peers - * List of peers to put in the PLACE record to advertise - * as entry points to the place in addition to the origin. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param password - * Password used to encrypt the record or NULL to keep it cleartext. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb + * @param nym + * Pseudonym. + * + * @return Hash of the public key of @a nym. */ -void -GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst, - const char *name, - uint32_t peer_count, - const struct GNUNET_PeerIdentity *peers, - struct GNUNET_TIME_Absolute expiration_time, - const char *password, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls) +const struct GNUNET_HashCode * +GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym) { - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - if (NULL == namestore) - namestore = GNUNET_NAMESTORE_connect (plc->cfg); - if (NULL == core) - core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL, - NULL, GNUNET_NO, NULL, GNUNET_NO, NULL); - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = expiration_time.abs_value_us; - - struct GNUNET_GNSRECORD_PlaceData * - rec = GNUNET_malloc (sizeof (*rec) + peer_count * sizeof (*peers)); - rec->place_key = plc->pub_key; - rec->origin = this_peer; - rec->relay_count = htonl (peer_count); - memcpy (&rec[1], peers, peer_count * sizeof (*peers)); - - rd.data = rec; - rd.data_size = sizeof (*rec) + peer_count * sizeof (*peers); - - GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key, - name, 1, &rd, result_cb, result_cls); + return &nym->pub_key_hash; } @@ -1966,65 +2089,117 @@ GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst) } + +void +place_leave (struct GNUNET_SOCIAL_Place *plc) +{ + struct GNUNET_MessageHeader msg; + msg.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); + msg.size = htons (sizeof (msg)); + GNUNET_CLIENT_MANAGER_transmit (plc->client, &msg); +} + + +void +place_disconnect (struct GNUNET_SOCIAL_Place *plc, + GNUNET_ContinuationCallback disconnect_cb, + void *disconnect_cls) +{ + plc->is_disconnecting = GNUNET_YES; + plc->disconnect_cb = disconnect_cb; + plc->disconnect_cls = disconnect_cls; + + GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES, + GNUNET_YES == plc->is_host + ? host_cleanup : guest_cleanup, + plc); +} + + /** - * Stop hosting a place. + * Disconnect from a home. * * Invalidates host handle. * - * @param host Host leaving the place. - * @param keep_active Keep the place active after last host disconnected. + * @param hst + * The host to disconnect. */ void -GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, - int keep_active, - GNUNET_ContinuationCallback leave_cb, - void *leave_cls) +GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) { - struct GNUNET_SOCIAL_Place *plc = &hst->plc; + place_disconnect (&hst->plc, disconnect_cb, cls); +} - /* FIXME: send msg to service */ - plc->is_disconnecting = GNUNET_YES; - plc->disconnect_cb = leave_cb; - plc->disconnect_cls = leave_cls; - - GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES, - &host_cleanup, hst); +/** + * Stop hosting the home. + * + * Sends a _notice_place_closed announcement to the home. + * Invalidates host handle. + * + * @param hst + * The host leaving. + * @param env + * Environment for the message or NULL. + * _nym is set to @e nym regardless whether an @e env is provided. + * @param disconnect_cb + * Function called after the host left the place + * and disconnected from the social service. + * @param cls + * Closure for @a disconnect_cb. + */ +void +GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, + const struct GNUNET_ENV_Environment *env, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) +{ + GNUNET_SOCIAL_host_announce (hst, "_notice_place_closed", env, NULL, NULL, + GNUNET_SOCIAL_ANNOUNCE_NONE); + place_leave (&hst->plc); + GNUNET_SOCIAL_host_disconnect (hst, disconnect_cb, cls); } /*** GUEST ***/ static struct GuestEnterRequest * -guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, +guest_enter_request_create (const char *app_id, + const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, const struct GNUNET_PeerIdentity *origin, size_t relay_count, const struct GNUNET_PeerIdentity *relays, const struct GNUNET_PSYC_Message *join_msg) { + uint16_t app_id_size = strlen (app_id) + 1; uint16_t join_msg_size = ntohs (join_msg->header.size); uint16_t relay_size = relay_count * sizeof (*relays); struct GuestEnterRequest * - req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size); + greq = GNUNET_malloc (sizeof (*greq) + app_id_size + relay_size + join_msg_size); + + greq->header.size = htons (sizeof (*greq) + app_id_size + relay_size + join_msg_size); + greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); + greq->place_pub_key = *place_pub_key; + greq->ego_pub_key = *ego_pub_key; + greq->origin = *origin; + greq->relay_count = htonl (relay_count); - req->header.size = htons (sizeof (*req) + relay_size + join_msg_size); - req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); - req->place_key = *place_key; - req->guest_key = *guest_key; - req->origin = *origin; - req->relay_count = htonl (relay_count); + char *p = (char *) &greq[1]; + memcpy (p, app_id, app_id_size); + p += app_id_size; - uint16_t p = sizeof (*req); if (0 < relay_size) { - memcpy ((char *) req + p, relays, relay_size); + memcpy (p, relays, relay_size); p += relay_size; } - memcpy ((char *) req + p, join_msg, join_msg_size); - return req; + memcpy (p, join_msg, join_msg_size); + return greq; } /** @@ -2045,13 +2220,13 @@ guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_ke * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, +GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, const struct GNUNET_PeerIdentity *origin, uint32_t relay_count, const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *join_msg, + const struct GNUNET_PSYC_Message *entry_msg, struct GNUNET_SOCIAL_Slicer *slicer, GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, @@ -2060,9 +2235,9 @@ GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); struct GNUNET_SOCIAL_Place *plc = &gst->plc; - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - plc->pub_key = *place_key; - plc->cfg = cfg; + plc->ego_pub_key = ego->pub_key; + plc->pub_key = *place_pub_key; + plc->cfg = app->cfg; plc->is_host = GNUNET_YES; plc->slicer = slicer; @@ -2070,86 +2245,22 @@ GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, gst->entry_dcsn_cb = entry_dcsn_cb; gst->cb_cls = cls; - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers); + plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", guest_handlers); GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc)); plc->tmit = GNUNET_PSYC_transmit_create (plc->client); plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); struct GuestEnterRequest * - req = guest_enter_request_create (&plc->ego_key, place_key, origin, - relay_count, relays, join_msg); - plc->connect_msg = &req->header; + greq = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key, + origin, relay_count, relays, entry_msg); + plc->connect_msg = &greq->header; place_send_connect_msg (plc); return gst; } /** - * Result of a GNS name lookup for entering a place. - * - * @see GNUNET_SOCIAL_guest_enter_by_name - */ -static void -gns_result_guest_enter (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct GNUNET_SOCIAL_Guest *gst = cls; - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p GNS result: %u records.\n", gst, rd_count); - - const struct GNUNET_GNSRECORD_PlaceData * - rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data; - - if (0 == rd_count) - { - if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0); - return; - } - - if (rd->data_size < sizeof (*rec)) - { - GNUNET_break_op (0); - if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0); - return; - } - - uint16_t relay_count = ntohl (rec->relay_count); - struct GNUNET_PeerIdentity *relays = NULL; - - if (0 < relay_count) - { - if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity)) - { - relays = (struct GNUNET_PeerIdentity *) &rec[1]; - } - else - { - relay_count = 0; - GNUNET_break_op (0); - } - } - - struct GuestEnterRequest * - req = guest_enter_request_create (&plc->ego_key, &rec->place_key, - &rec->origin, relay_count, relays, - (struct GNUNET_PSYC_Message *) plc->connect_msg); - GNUNET_free (plc->connect_msg); - plc->connect_msg = &req->header; - plc->pub_key = req->place_key; - - plc->tmit = GNUNET_PSYC_transmit_create (plc->client); - plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); - - place_send_connect_msg (plc); -} - - -/** * Request entry to a place by name as a guest. * * @param cfg @@ -2165,7 +2276,7 @@ gns_result_guest_enter (void *cls, uint32_t rd_count, * @param password * Password to decrypt the record, or NULL for cleartext records. * @param join_msg - * Entry request message. + * Entry request message or NULL. * @param slicer * Slicer to use for processing incoming requests from guests. * @param local_enter_cb @@ -2176,9 +2287,10 @@ gns_result_guest_enter (void *cls, uint32_t rd_count, * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *gns_name, const char *password, +GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *gns_name, + const char *password, const struct GNUNET_PSYC_Message *join_msg, struct GNUNET_SOCIAL_Slicer *slicer, GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, @@ -2188,32 +2300,109 @@ GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); struct GNUNET_SOCIAL_Place *plc = &gst->plc; - GNUNET_assert (NULL != join_msg); + if (NULL == password) + password = ""; + + uint16_t app_id_size = strlen (app->id) + 1; + uint16_t gns_name_size = strlen (gns_name) + 1; + uint16_t password_size = strlen (password) + 1; + + uint16_t join_msg_size = 0; + if (NULL != join_msg); + join_msg_size = ntohs (join_msg->header.size); + + uint16_t greq_size = sizeof (struct GuestEnterByNameRequest) + + app_id_size + gns_name_size + password_size + join_msg_size; + struct GuestEnterByNameRequest *greq = GNUNET_malloc (greq_size); + greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME); + greq->header.size = htons (greq_size); + greq->ego_pub_key = ego->pub_key; + + char *p = (char *) &greq[1]; + memcpy (p, app->id, app_id_size); + p += app_id_size; + memcpy (p, gns_name, gns_name_size); + p += gns_name_size; + memcpy (p, password, password_size); + p += password_size; + if (NULL != join_msg) + memcpy (p, join_msg, join_msg_size); gst->enter_cb = local_enter_cb; gst->entry_dcsn_cb = entry_decision_cb; gst->cb_cls = cls; - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - plc->cfg = cfg; + plc->ego_pub_key = ego->pub_key; + plc->cfg = app->cfg; plc->is_host = GNUNET_NO; plc->slicer = slicer; - uint16_t join_msg_size = ntohs (join_msg->header.size); - plc->connect_msg = GNUNET_malloc (join_msg_size); - memcpy (plc->connect_msg, join_msg, join_msg_size); + plc->client = GNUNET_CLIENT_MANAGER_connect (app->cfg, "social", guest_handlers); + GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc)); + + plc->tmit = GNUNET_PSYC_transmit_create (plc->client); + plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); + + plc->connect_msg = &greq->header; + place_send_connect_msg (plc); + + return gst; +} - if (NULL == gns) - gns = GNUNET_GNS_connect (cfg); - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers); +/** + * Reconnect to an already entered place as guest. + * + * @param gconn + * Guest connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() + * @param slicer + * Slicer to use for processing incoming requests from guests. + * @param local_enter_cb + * Called upon connection established to the social service. + * @param entry_decision_cb + * Called upon receiving entry decision. + * + * @return NULL on errors, otherwise handle for the guest. + */ +struct GNUNET_SOCIAL_Guest * +GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, + struct GNUNET_SOCIAL_Slicer *slicer, + GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); + struct GNUNET_SOCIAL_Place *plc = &gst->plc; + + uint16_t app_id_size = strlen (gconn->app->id) + 1; + uint16_t greq_size = sizeof (struct GuestEnterRequest) + app_id_size; + struct GuestEnterRequest *greq = GNUNET_malloc (greq_size); + greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); + greq->header.size = htons (greq_size); + greq->ego_pub_key = gconn->plc_msg.ego_pub_key; + greq->place_pub_key = gconn->plc_msg.place_pub_key; + + memcpy (&greq[1], gconn->app->id, app_id_size); + + gst->enter_cb = local_enter_cb; + gst->cb_cls = cls; + + plc->cfg = gconn->app->cfg; + plc->is_host = GNUNET_NO; + plc->slicer = slicer; + plc->pub_key = gconn->plc_msg.place_pub_key; + plc->ego_pub_key = gconn->plc_msg.ego_pub_key; + + plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", guest_handlers); GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc)); - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key); - GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key, - GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT, - NULL, gns_result_guest_enter, gst); + plc->tmit = GNUNET_PSYC_transmit_create (plc->client); + plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); + + plc->connect_msg = &greq->header; + place_send_connect_msg (plc); + + GNUNET_free (gconn); return gst; } @@ -2284,6 +2473,23 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) /** + * Disconnect from a place. + * + * Invalidates guest handle. + * + * @param gst + * The guest to disconnect. + */ +void +GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) +{ + place_disconnect (&gst->plc, disconnect_cb, cls); +} + + +/** * Leave a place temporarily or permanently. * * Notifies the owner of the place about leaving, and destroys the place handle. @@ -2301,28 +2507,14 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) */ void GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, - int keep_active, struct GNUNET_ENV_Environment *env, - GNUNET_ContinuationCallback leave_cb, - void *leave_cls) + GNUNET_ContinuationCallback disconnect_cb, + void *cls) { - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - plc->is_disconnecting = GNUNET_YES; - plc->disconnect_cb = leave_cb; - plc->disconnect_cls = leave_cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Guest: leaving place.\n"); - - if (GNUNET_NO == keep_active && NULL != plc->tmit) - { - GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, - GNUNET_SOCIAL_TALK_NONE); - } - - GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES, - &guest_cleanup, gst); + GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, + GNUNET_SOCIAL_TALK_NONE); + place_leave (&gst->plc); + GNUNET_SOCIAL_guest_disconnect (gst, disconnect_cb, cls); } @@ -2342,6 +2534,21 @@ GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst) } +/** + * Obtain the public key of a place. + * + * @param plc + * Place. + * + * @return Public key of the place. + */ +const struct GNUNET_CRYPTO_EddsaPublicKey * +GNUNET_SOCIAL_place_get_key (struct GNUNET_SOCIAL_Place *plc) +{ + return &plc->pub_key; +} + + static struct GNUNET_SOCIAL_HistoryRequest * place_history_replay (struct GNUNET_SOCIAL_Place *plc, uint64_t start_message_id, @@ -2571,8 +2778,119 @@ GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) } +static void +op_recv_zone_add_place_result (void *cls, int64_t result, + const void *err_msg, uint16_t err_msg_size) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received zone add place result: %" PRId64 ".\n", result); + + struct ZoneAddPlaceHandle *add_plc = cls; + if (NULL != add_plc->result_cb) + add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size); + + GNUNET_free (add_plc->req); + GNUNET_free (add_plc); +} + + /** - * Add public key to the GNS zone of the @e ego. + * Advertise @e place in the GNS zone of @e ego. + * + * @param app + * Application handle. + * @param ego + * Ego. + * @param place_pub_key + * Public key of place to add. + * @param name + * The name for the PLACE record to put in the zone. + * @param password + * Password used to encrypt the record or NULL to keep it cleartext. + * @param relay_count + * Number of elements in the @a relays array. + * @param relays + * List of relays to put in the PLACE record to advertise + * as entry points to the place in addition to the origin. + * @param expiration_time + * Expiration time of the record, use 0 to remove the record. + * @param result_cb + * Function called with the result of the operation. + * @param result_cls + * Closure for @a result_cb + * + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name/password is too long. + */ +int +GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const char *password, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, + const struct GNUNET_PeerIdentity *origin, + uint32_t relay_count, + const struct GNUNET_PeerIdentity *relays, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls) +{ + struct ZoneAddPlaceRequest *preq; + size_t name_size = strlen (name) + 1; + size_t password_size = strlen (password) + 1; + size_t relay_size = relay_count * sizeof (*relays); + size_t preq_size = sizeof (*preq) + name_size + password_size + relay_size; + + if (GNUNET_SERVER_MAX_MESSAGE_SIZE < preq_size) + return GNUNET_SYSERR; + + preq = GNUNET_malloc (preq_size); + preq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE); + preq->header.size = htons (preq_size); + preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); + preq->ego_pub_key = ego->pub_key; + preq->place_pub_key = *place_pub_key; + preq->origin = *origin; + preq->relay_count = htonl (relay_count); + + char *p = (char *) &preq[1]; + memcpy (p, name, name_size); + p += name_size; + memcpy (p, password, password_size); + p += password_size; + memcpy (p, relays, relay_size); + + struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc)); + add_plc->req = preq; + add_plc->result_cb = result_cb; + add_plc->result_cls = result_cls; + + preq->op_id = GNUNET_htonll (GNUNET_CLIENT_MANAGER_op_add (app->client, + op_recv_zone_add_place_result, + add_plc)); + GNUNET_CLIENT_MANAGER_transmit_now (app->client, &preq->header); + return GNUNET_OK; +} + + +static void +op_recv_zone_add_nym_result (void *cls, int64_t result, + const void *err_msg, uint16_t err_msg_size) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received zone add nym result: %" PRId64 ".\n", result); + + struct ZoneAddNymHandle *add_nym = cls; + if (NULL != add_nym->result_cb) + add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size); + + GNUNET_free (add_nym->req); + GNUNET_free (add_nym); +} + + +/** + * Add nym to the GNS zone of @e ego. * * @param cfg * Configuration. @@ -2588,43 +2906,57 @@ GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) * Function called with the result of the operation. * @param result_cls * Closure for @a result_cb + * + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name is too long. */ -void -GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls) -{ - if (NULL == namestore) - namestore = GNUNET_NAMESTORE_connect (cfg); - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = expiration_time.abs_value_us; - rd.data = nym_pub_key; - rd.data_size = sizeof (*nym_pub_key); +int +GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls) +{ + struct ZoneAddNymRequest *nreq; + + size_t name_size = strlen (name) + 1; + if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size) + return GNUNET_SYSERR; - GNUNET_NAMESTORE_records_store (namestore, - GNUNET_IDENTITY_ego_get_private_key (ego), - name, 1, &rd, result_cb, result_cls); + nreq = GNUNET_malloc (sizeof (*nreq) + name_size); + nreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM); + nreq->header.size = htons (sizeof (*nreq) + name_size); + nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); + nreq->ego_pub_key = ego->pub_key; + nreq->nym_pub_key = *nym_pub_key; + memcpy (&nreq[1], name, name_size); + + struct ZoneAddNymHandle * add_nym = GNUNET_malloc (sizeof (*add_nym)); + add_nym->req = nreq; + add_nym->result_cb = result_cb; + add_nym->result_cls = result_cls; + + nreq->op_id = GNUNET_htonll (GNUNET_CLIENT_MANAGER_op_add (app->client, + op_recv_zone_add_nym_result, + add_nym)); + GNUNET_CLIENT_MANAGER_transmit_now (app->client, &nreq->header); + return GNUNET_OK; } /** - * Start listening for entered places as host or guest. + * Connect application to the social service. * - * The @notify_host and @notify_guest functions are - * initially called with the full list of entered places, - * then later each time a new place is entered. + * The @host_place_cb and @guest_place_cb functions are + * initially called for each entered places, + * then later each time a new place is entered with the current application ID. * * @param cfg * Configuration. - * @param ego - * Listen for places of this ego. + * @param id + * Application ID. * @param notify_host * Function to notify about a place entered as host. * @param notify_guest @@ -2634,48 +2966,81 @@ GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg, * * @return Handle that can be used to stop listening. */ -struct GNUNET_SOCIAL_PlaceListenHandle * -GNUNET_SOCIAL_place_listen_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - GNUNET_SOCIAL_PlaceNotifyHostCallback notify_host, - GNUNET_SOCIAL_PlaceNotifyGuestCallback notify_guest, - void *notify_cls) -{ - struct GNUNET_SOCIAL_PlaceListenHandle *pl = GNUNET_malloc (sizeof *pl); - pl->notify_host = notify_host; - pl->notify_guest = notify_guest; - pl->notify_cls = notify_cls; - - struct GNUNET_SOCIAL_Place *plc = &pl->plc; - - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - plc->cfg = cfg; - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", - notify_handlers); - GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, pl, sizeof (*pl)); - - struct PlaceListenRequest *req = GNUNET_malloc (sizeof (*req)); - req->ego_key = plc->ego_key; - req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN); - req->header.size = htons (sizeof (*req)); - - plc->connect_msg = (struct GNUNET_MessageHeader *) req; - place_send_connect_msg (plc); +struct GNUNET_SOCIAL_App * +GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *id, + GNUNET_SOCIAL_AppEgoCallback ego_cb, + GNUNET_SOCIAL_AppHostPlaceCallback host_cb, + GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, + void *cls) +{ + uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE); + if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size) + return NULL; + app_id_size++; + + struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app); + app->cfg = cfg; + app->ego_cb = ego_cb; + app->host_cb = host_cb; + app->guest_cb = guest_cb; + app->cb_cls = cls; + app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + app->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", + app_handlers); + GNUNET_CLIENT_MANAGER_set_user_context_ (app->client, app, sizeof (*app)); - return pl; + app->id = GNUNET_malloc (app_id_size); + memcpy (app->id, id, app_id_size); + + struct AppConnectRequest *creq = GNUNET_malloc (sizeof (*creq) + app_id_size); + creq->header.size = htons (sizeof (*creq) + app_id_size); + creq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT); + memcpy (&creq[1], app->id, app_id_size); + + app->connect_msg = &creq->header; + app_send_connect_msg (app); + + return app; +} + + +/** + * Disconnect application. + * + * @param app + * Application handle. + */ +void +GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app) +{ + GNUNET_CLIENT_MANAGER_disconnect (app->client, GNUNET_NO, NULL, NULL); } /** - * Stop listening for entered places. + * Detach application from a place. * - * @param pl - * Place listen handle. + * Removes the place from the entered places list for this application. + * Note: this does not disconnect from the place. + * + * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect() + * + * @param app + * Application. + * @param plc + * Place. */ void -GNUNET_SOCIAL_place_listen_stop (struct GNUNET_SOCIAL_PlaceListenHandle *pl) +GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app, + struct GNUNET_SOCIAL_Place *plc) { - GNUNET_CLIENT_MANAGER_disconnect (pl->plc.client, GNUNET_NO, NULL, NULL); + struct AppDetachRequest dreq; + dreq.header.size = htons (sizeof (dreq)); + dreq.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH); + dreq.place_pub_key = plc->pub_key; + GNUNET_CLIENT_MANAGER_transmit_now (plc->client, &dreq.header); } + /* end of social_api.c */ diff --git a/src/social/test_social.c b/src/social/test_social.c index 158fa469d3..38710cd1a0 100644 --- a/src/social/test_social.c +++ b/src/social/test_social.c @@ -45,6 +45,9 @@ */ int res; +struct GNUNET_SOCIAL_App *app; +const char *app_id = "test"; + /** * Handle for task for timeout termination. */ @@ -57,8 +60,8 @@ struct GNUNET_PeerIdentity this_peer; struct GNUNET_IDENTITY_Handle *id; -const struct GNUNET_IDENTITY_Ego *host_ego; -const struct GNUNET_IDENTITY_Ego *guest_ego; +const struct GNUNET_SOCIAL_Ego *host_ego; +const struct GNUNET_SOCIAL_Ego *guest_ego; const char *host_name = "Host One"; const char *guest_name = "Guest One"; @@ -67,6 +70,8 @@ struct GNUNET_CRYPTO_EddsaPrivateKey *place_key; struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key; struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; +struct GNUNET_HashCode place_pub_hash; + struct GNUNET_CRYPTO_EcdsaPublicKey guest_pub_key; struct GNUNET_CRYPTO_EcdsaPublicKey host_pub_key; @@ -111,32 +116,57 @@ struct GNUNET_PSYC_Message *join_resp; uint32_t counter; -uint8_t guest_pkey_added = GNUNET_NO; +uint8_t is_guest_nym_added = GNUNET_NO; +uint8_t is_host_reconnected = GNUNET_NO; +uint8_t is_guest_reconnected = GNUNET_NO; enum { - TEST_NONE = 0, - TEST_HOST_ANSWER_DOOR_REFUSE = 1, - TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 2, - TEST_HOST_ANSWER_DOOR_ADMIT = 3, - TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 4, - TEST_HOST_ANNOUNCE = 5, - TEST_HOST_ANNOUNCE_END = 6, - TEST_HOST_ANNOUNCE2 = 7, - TEST_HOST_ANNOUNCE2_END = 8, - TEST_GUEST_TALK = 9, - TEST_GUEST_HISTORY_REPLAY = 10, - TEST_GUEST_HISTORY_REPLAY_LATEST = 11, - TEST_GUEST_LOOK_AT = 12, - TEST_GUEST_LOOK_FOR = 13, - TEST_GUEST_LEAVE = 14, - TEST_HOST_ADVERTISE = 15, - TEST_GUEST_ENTER_BY_NAME = 16, - TEST_HOST_LEAVE = 17, + TEST_NONE = 0, + TEST_HOST_CREATE = 1, + TEST_HOST_ENTER = 2, + TEST_GUEST_CREATE = 3, + TEST_GUEST_ENTER = 4, + TEST_HOST_ANSWER_DOOR_REFUSE = 5, + TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 6, + TEST_HOST_ANSWER_DOOR_ADMIT = 7, + TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 8, + TEST_HOST_ANNOUNCE = 9, + TEST_HOST_ANNOUNCE_END = 10, + TEST_HOST_ANNOUNCE2 = 11, + TEST_HOST_ANNOUNCE2_END = 12, + TEST_GUEST_TALK = 13, + TEST_GUEST_HISTORY_REPLAY = 14, + TEST_GUEST_HISTORY_REPLAY_LATEST = 15, + TEST_GUEST_LOOK_AT = 16, + TEST_GUEST_LOOK_FOR = 17, + TEST_GUEST_LEAVE = 18, + TEST_ZONE_ADD_PLACE = 19, + TEST_GUEST_ENTER_BY_NAME = 20, + TEST_RECONNECT = 21, + TEST_GUEST_LEAVE2 = 22, + TEST_HOST_LEAVE = 23, } test; static void +schedule_guest_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +static void +host_answer_door (void *cls, + struct GNUNET_SOCIAL_Nym *nym, + const char *method_name, + struct GNUNET_ENV_Environment *env, + size_t data_size, + const void *data); + +static void +host_enter (); + +static void +guest_init (); + +static void guest_enter (); static void @@ -167,18 +197,31 @@ cleanup () id = NULL; } + if (NULL != guest_slicer) + { + GNUNET_SOCIAL_slicer_destroy (guest_slicer); + guest_slicer = NULL; + } + + if (NULL != host_slicer) + { + GNUNET_SOCIAL_slicer_destroy (host_slicer); + host_slicer = NULL; + } + if (NULL != gst) { - GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, NULL, NULL, NULL); + GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL); gst = NULL; gst_plc = NULL; } if (NULL != hst) { - GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, NULL, NULL); + GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL); hst = NULL; hst_plc = NULL; } + GNUNET_SOCIAL_app_disconnect (app); GNUNET_SCHEDULER_shutdown (); } @@ -295,58 +338,186 @@ host_left () { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "The host has left the place.\n"); - GNUNET_SOCIAL_slicer_destroy (host_slicer); - host_slicer = NULL; + end (); +} + + +static void +schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + test = TEST_HOST_LEAVE; + GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL); hst = NULL; hst_plc = NULL; +} - // TODO: GNUNET_SOCIAL_place_listen_start () - end (); +static void +host_farewell2 (void *cls, + const struct GNUNET_SOCIAL_Nym *nym, + struct GNUNET_ENV_Environment *env) +{ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Nym left the place again.\n"); + GNUNET_SCHEDULER_add_now (schedule_host_leave, NULL); } static void -schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +host_reconnected (void *cls, int result, + const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, + uint64_t max_message_id) { - test = TEST_HOST_LEAVE; - GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, &host_left, NULL); + place_pub_key = *home_pub_key; + GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Test #%u: Host reconnected to place %s\n", + test, GNUNET_h2s (&place_pub_hash)); + + is_host_reconnected = GNUNET_YES; + if (GNUNET_YES == is_guest_reconnected) + { + GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL); + } } static void -id_guest_ego_cb2 (void *cls, const struct GNUNET_IDENTITY_Ego *ego) +guest_reconnected (void *cls, int result, uint64_t max_message_id) { - GNUNET_assert (NULL != ego); - guest_ego = ego; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Test #%u: Guest reconnected to place: %d\n", + test, result); + GNUNET_assert (0 <= result); - guest_enter_by_name (); + is_guest_reconnected = GNUNET_YES; + if (GNUNET_YES == is_host_reconnected) + { + GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL); + } } static void -host_recv_advertise_result (void *cls, int32_t success, const char *emsg) +app_recv_host (void *cls, + struct GNUNET_SOCIAL_HostConnection *hconn, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key) +{ + struct GNUNET_HashCode host_pub_hash; + GNUNET_CRYPTO_hash (host_pub_key, sizeof (*host_pub_key), &host_pub_hash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got app host place notification: %s\n", + GNUNET_h2s (&host_pub_hash)); + + if (test == TEST_RECONNECT) + { + if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key))) + { + hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer, host_reconnected, + host_answer_door, host_farewell2, NULL); + } + } +} + + +static void +app_recv_guest (void *cls, + struct GNUNET_SOCIAL_GuestConnection *gconn, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key) +{ + struct GNUNET_HashCode guest_pub_hash; + GNUNET_CRYPTO_hash (guest_pub_key, sizeof (*guest_pub_key), &guest_pub_hash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got app guest place notification: %s\n", + GNUNET_h2s (&guest_pub_hash)); + + if (test == TEST_RECONNECT) + { + if (0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key))) + { + gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, guest_slicer, + guest_reconnected, NULL); + } + } +} + + +static void +app_recv_ego (void *cls, + struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, + const char *name) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Test #%u: Advertise result: %d (%s).\n", - test, success, emsg); - GNUNET_assert (GNUNET_YES == success); + "Got app ego notification: %p %s %s\n", + ego, name, + GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key)); + + if (NULL != strstr (name, host_name) && TEST_HOST_CREATE == test) + { + host_ego = ego; + host_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (host_ego)); + GNUNET_assert (TEST_HOST_CREATE == test); + host_enter (); + } + else if (NULL != strstr (name, guest_name)) + { + guest_ego = ego; + + if (TEST_GUEST_CREATE == test) + guest_init (); + } +} + + +static void +schedule_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + test = TEST_RECONNECT; - GNUNET_assert (GNUNET_YES == guest_pkey_added); - GNUNET_IDENTITY_ego_lookup (cfg, guest_name, id_guest_ego_cb2, NULL); + GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL); + GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL); + hst = NULL; + gst = NULL; + + GNUNET_SOCIAL_app_disconnect (app); + app = GNUNET_SOCIAL_app_connect (cfg, app_id, + app_recv_ego, + app_recv_host, + app_recv_guest, + NULL); } static void -host_advertise () +host_recv_zone_add_place_result (void *cls, int64_t result, + const void *data, uint16_t data_size) { - test = TEST_HOST_ADVERTISE; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Test #%u: Advertising place.\n", test); + "Test #%u: Zone add place result: %d (%.*s).\n", + test, result, data_size, data); + GNUNET_assert (GNUNET_YES == result); - GNUNET_SOCIAL_host_advertise (hst, "home", 1, &this_peer, + GNUNET_assert (GNUNET_YES == is_guest_nym_added); + guest_enter_by_name (); +} + + +static void +zone_add_place () +{ + test = TEST_ZONE_ADD_PLACE; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Test #%u: Adding place to zone.\n", test); + + GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!", + &place_pub_key, &this_peer, 1, &this_peer, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), - "let.me*in!", host_recv_advertise_result, hst); + host_recv_zone_add_place_result, app); } @@ -356,12 +527,12 @@ host_farewell (void *cls, struct GNUNET_ENV_Environment *env) { const struct GNUNET_CRYPTO_EcdsaPublicKey * - nym_key = GNUNET_SOCIAL_nym_get_key (nym); + nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Farewell: nym %s (%s) has left the place.\n", - GNUNET_h2s (GNUNET_SOCIAL_nym_get_key_hash (nym)), str); + GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str); GNUNET_free (str); GNUNET_assert (1 == GNUNET_ENV_environment_get_count (env)); if (0 != memcmp (&guest_pub_key, nym_key, sizeof (*nym_key))) @@ -372,7 +543,7 @@ host_farewell (void *cls, GNUNET_free (str); GNUNET_assert (0); } - host_advertise (); + zone_add_place (); } @@ -381,25 +552,24 @@ guest_left (void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "The guest has left the place.\n"); - GNUNET_SOCIAL_slicer_destroy (guest_slicer); - guest_slicer = NULL; - gst = NULL; - gst_plc = NULL; } static void guest_leave() { - test = TEST_GUEST_LEAVE; + if (test < TEST_RECONNECT) + test = TEST_GUEST_LEAVE; + else + test = TEST_GUEST_LEAVE2; struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create (); GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET, "_message", DATA2ARG ("Leaving.")); - GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, env, &guest_left, NULL); + GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL); GNUNET_ENV_environment_destroy (env); - - /* @todo test keep_active */ + gst = NULL; + gst_plc = NULL; } @@ -871,7 +1041,7 @@ guest_recv_entry_decision (void *cls, break; case TEST_GUEST_ENTER_BY_NAME: - GNUNET_SCHEDULER_add_now (schedule_host_leave, NULL); + GNUNET_SCHEDULER_add_now (schedule_reconnect, NULL); break; default: @@ -951,7 +1121,7 @@ guest_enter () emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, emsg->data, emsg->data_size); - gst = GNUNET_SOCIAL_guest_enter (cfg, guest_ego, &place_pub_key, + gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key, &this_peer, 0, NULL, emsg->msg, guest_slicer, guest_recv_local_enter, guest_recv_entry_decision, NULL); @@ -979,7 +1149,7 @@ guest_enter_by_name () emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, emsg->data, emsg->data_size); - gst = GNUNET_SOCIAL_guest_enter_by_name (cfg, guest_ego, + gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego, "home.host.gnu", "let.me*in!", emsg->msg, guest_slicer, guest_recv_local_enter, @@ -989,19 +1159,18 @@ guest_enter_by_name () static void -guest_recv_add_pkey_result (void *cls, int32_t success, const char *emsg) +app_recv_zone_add_nym_result (void *cls, int64_t result, + const void *data, uint16_t data_size) { - GNUNET_assert (GNUNET_YES == success); - guest_pkey_added = GNUNET_YES; + GNUNET_assert (GNUNET_YES == result); + is_guest_nym_added = GNUNET_YES; } static void -id_guest_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego) +guest_init () { - GNUNET_assert (NULL != ego); - guest_ego = ego; - GNUNET_IDENTITY_ego_get_public_key (ego, &guest_pub_key); + guest_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (guest_ego)); guest_slicer = GNUNET_SOCIAL_slicer_create (); GNUNET_SOCIAL_slicer_method_add (guest_slicer, "", @@ -1011,10 +1180,9 @@ id_guest_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego) guest_recv_mod_foo_bar, &mod_foo_bar_rcls); test = TEST_HOST_ANSWER_DOOR_ADMIT; - GNUNET_SOCIAL_zone_add_pkey (cfg, guest_ego, "host", &host_pub_key, - GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), - guest_recv_add_pkey_result, NULL); - + GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", &host_pub_key, + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), + app_recv_zone_add_nym_result, NULL); guest_enter (); } @@ -1030,37 +1198,40 @@ id_guest_created (void *cls, const char *emsg) GNUNET_assert (0); #endif } - - GNUNET_IDENTITY_ego_lookup (cfg, guest_name, &id_guest_ego_cb, NULL); + if (NULL != guest_ego) + guest_init (); } static void -host_entered (void *cls, int result, uint64_t max_message_id) +host_entered (void *cls, int result, + const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, + uint64_t max_message_id) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Host entered to place.\n"); + place_pub_key = *home_pub_key; + GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Host entered to place %s\n", GNUNET_h2s (&place_pub_hash)); + test = TEST_GUEST_CREATE; GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL); } static void -id_host_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego) +host_enter () { - GNUNET_assert (NULL != ego); - host_ego = ego; - GNUNET_IDENTITY_ego_get_public_key (ego, &host_pub_key); - host_slicer = GNUNET_SOCIAL_slicer_create (); GNUNET_SOCIAL_slicer_method_add (host_slicer, "", &host_recv_method, &host_recv_modifier, &host_recv_data, &host_recv_eom, NULL); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Entering to place as host.\n"); - hst = GNUNET_SOCIAL_host_enter (cfg, host_ego, place_key, - GNUNET_PSYC_CHANNEL_PRIVATE, host_slicer, - host_entered, host_answer_door, - host_farewell, NULL); + test = TEST_HOST_ENTER; + hst = GNUNET_SOCIAL_host_enter (app, host_ego, + GNUNET_PSYC_CHANNEL_PRIVATE, + host_slicer, host_entered, + host_answer_door, host_farewell, NULL); hst_plc = GNUNET_SOCIAL_host_get_place (hst); } @@ -1068,6 +1239,12 @@ id_host_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego) static void id_host_created (void *cls, const char *emsg) { + if (NULL != core) + { + GNUNET_CORE_disconnect (core); + core = NULL; + } + if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -1077,7 +1254,11 @@ id_host_created (void *cls, const char *emsg) #endif } - GNUNET_IDENTITY_ego_lookup (cfg, host_name, &id_host_ego_cb, NULL); + app = GNUNET_SOCIAL_app_connect (cfg, app_id, + app_recv_ego, + app_recv_host, + app_recv_guest, + NULL); } @@ -1085,7 +1266,6 @@ static void identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, const char *name) { - } @@ -1093,8 +1273,9 @@ static void core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity) { this_peer = *my_identity; - id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL); + + test = TEST_HOST_CREATE; GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL); } @@ -1119,9 +1300,6 @@ run (void *cls, cfg = c; end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); - place_key = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_CRYPTO_eddsa_key_get_public (place_key, &place_pub_key); - core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, NULL); } |