2 * This file is part of GNUnet
3 * Copyright (C) 2013 Christian Grothoff (and other contributing authors)
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * @file social/gnunet-service-social.c
23 * @brief Social service
24 * @author Gabor X Toth
30 #include "gnunet_util_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_psyc_service.h"
35 #include "gnunet_psyc_util_lib.h"
36 #include "gnunet_social_service.h"
41 * Handle to our current configuration.
43 static const struct GNUNET_CONFIGURATION_Handle *cfg;
46 * Handle to the statistics service.
48 static struct GNUNET_STATISTICS_Handle *stats;
51 * Notification context, simplifies client broadcasts.
53 static struct GNUNET_SERVER_NotificationContext *nc;
56 * All connected hosts.
57 * Place's pub_key_hash -> struct Host
59 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
62 * All connected guests.
63 * Place's pub_key_hash -> struct Guest
65 static struct GNUNET_CONTAINER_MultiHashMap *guests;
68 * Connected guests per place.
69 * Place's pub_key_hash -> Guest's pub_key -> struct Guest
71 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
75 * Message fragment transmission queue.
77 struct FragmentTransmitQueue
79 struct FragmentTransmitQueue *prev;
80 struct FragmentTransmitQueue *next;
82 struct GNUNET_SERVER_Client *client;
85 * Pointer to the next message part inside the data after this struct.
87 struct GNUNET_MessageHeader *next_part;
95 * @see enum GNUNET_PSYC_MessageState
99 /* Followed by one or more message parts. */
104 * Message transmission queue.
106 struct MessageTransmitQueue
108 struct MessageTransmitQueue *prev;
109 struct MessageTransmitQueue *next;
111 struct FragmentTransmitQueue *frags_head;
112 struct FragmentTransmitQueue *frags_tail;
114 struct GNUNET_SERVER_Client *client;
118 * List of connected clients.
120 struct ClientListItem
122 struct ClientListItem *prev;
123 struct ClientListItem *next;
125 struct GNUNET_SERVER_Client *client;
130 * Common part of the client context for both a host and guest.
134 struct ClientListItem *clients_head;
135 struct ClientListItem *clients_tail;
137 struct MessageTransmitQueue *tmit_msgs_head;
138 struct MessageTransmitQueue *tmit_msgs_tail;
140 struct GNUNET_PSYC_Channel *channel;
143 * Public key of the channel.
145 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
148 * Hash of @a pub_key.
150 struct GNUNET_HashCode pub_key_hash;
153 * Last message ID received for the place.
154 * 0 if there is no such message.
156 uint64_t max_message_id;
159 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
164 * Is this place ready to receive messages from client?
165 * #GNUNET_YES or #GNUNET_NO
170 * Is the client disconnected?
171 * #GNUNET_YES or #GNUNET_NO
173 uint8_t is_disconnected;
178 * Client context for a host.
183 * Place struct common for Host and Guest
188 * Private key of the channel.
190 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
193 * Handle for the multicast origin.
195 struct GNUNET_PSYC_Master *master;
198 * Transmit handle for multicast.
200 struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
203 * Incoming join requests.
204 * guest_key -> struct GNUNET_PSYC_JoinHandle *
206 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
209 * @see enum GNUNET_PSYC_Policy
211 enum GNUNET_PSYC_Policy policy;
216 * Client context for a guest.
221 * Place struct common for Host and Guest.
226 * Private key of the slave.
228 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
231 * Public key of the slave.
233 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
236 * Hash of @a pub_key.
238 struct GNUNET_HashCode pub_key_hash;
241 * Handle for the PSYC slave.
243 struct GNUNET_PSYC_Slave *slave;
246 * Transmit handle for multicast.
248 struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
251 * Peer identity of the origin.
253 struct GNUNET_PeerIdentity origin;
256 * Number of items in @a relays.
258 uint32_t relay_count;
261 * Relays that multicast can use to connect.
263 struct GNUNET_PeerIdentity *relays;
266 * Join request to be transmitted to the master on join.
268 struct GNUNET_MessageHeader *join_req;
271 * Join decision received from PSYC.
273 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
281 * Place where the client entered.
286 * Message queue for the message currently being transmitted
289 struct MessageTransmitQueue *tmit_msg;
293 struct OperationClosure
295 struct GNUNET_SERVER_Client *client;
303 psyc_transmit_message (struct Place *plc);
307 * Task run during shutdown.
313 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
317 GNUNET_SERVER_notification_context_destroy (nc);
322 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
329 * Clean up host data structures after a client disconnected.
332 cleanup_host (struct Host *hst)
334 struct Place *plc = &hst->plc;
336 if (NULL != hst->master)
337 GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
338 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
339 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
344 * Clean up guest data structures after a client disconnected.
347 cleanup_guest (struct Guest *gst)
349 struct Place *plc = &gst->plc;
350 struct GNUNET_CONTAINER_MultiHashMap *
351 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
353 GNUNET_assert (NULL != plc_gst); // FIXME
354 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst);
356 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
358 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
360 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
362 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
364 if (NULL != gst->join_req)
365 GNUNET_free (gst->join_req);
366 if (NULL != gst->relays)
367 GNUNET_free (gst->relays);
368 if (NULL != gst->slave)
369 GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
370 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
375 * Clean up place data structures after a client disconnected.
378 cleanup_place (struct Place *plc)
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 "%p Cleaning up place %s\n",
382 plc, GNUNET_h2s (&plc->pub_key_hash));
384 (GNUNET_YES == plc->is_host)
385 ? cleanup_host ((struct Host *) plc)
386 : cleanup_guest ((struct Guest *) plc);
392 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
399 * Called whenever a client is disconnected.
400 * Frees our resources associated with that client.
402 * @param cls Closure.
403 * @param client Identification of the client.
406 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
412 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
416 "%p User context is NULL in client_disconnect()\n", ctx);
421 struct Place *plc = ctx->plc;
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 "%p Client (%s) disconnected from place %s\n",
424 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
425 GNUNET_h2s (&plc->pub_key_hash));
427 struct ClientListItem *cli = plc->clients_head;
430 if (cli->client == client)
432 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
439 if (NULL == plc->clients_head)
440 { /* Last client disconnected. */
441 if (GNUNET_YES != plc->is_disconnected)
443 plc->is_disconnected = GNUNET_YES;
444 if (NULL != plc->tmit_msgs_head)
445 { /* Send pending messages to PSYC before cleanup. */
446 psyc_transmit_message (plc);
458 * Send message to all clients connected to the channel.
461 client_send_msg (const struct Place *plc,
462 const struct GNUNET_MessageHeader *msg)
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 "%p Sending message to clients.\n", plc);
467 struct ClientListItem *cli = plc->clients_head;
470 GNUNET_SERVER_notification_context_add (nc, cli->client);
471 GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, GNUNET_NO);
478 * Send a result code back to the client.
481 * Client that should receive the result code.
485 * Operation ID in network byte order.
487 * Data payload or NULL.
492 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
493 int64_t result_code, const void *data, uint16_t data_size)
495 struct GNUNET_OperationResultMessage *res;
497 res = GNUNET_malloc (sizeof (*res) + data_size);
498 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
499 res->header.size = htons (sizeof (*res) + data_size);
500 res->result_code = GNUNET_htonll (result_code);
503 memcpy (&res[1], data, data_size);
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506 "%p Sending result to client for operation #%" PRIu64 ": "
507 "%" PRId64 " (size: %u)\n",
508 client, GNUNET_ntohll (op_id), result_code, data_size);
510 GNUNET_SERVER_notification_context_add (nc, client);
511 GNUNET_SERVER_notification_context_unicast (nc, client, &res->header,
518 * Called after a PSYC master is started.
521 psyc_master_started (void *cls, int result, uint64_t max_message_id)
523 struct Host *hst = cls;
524 struct Place *plc = &hst->plc;
525 plc->max_message_id = max_message_id;
526 plc->is_ready = GNUNET_YES;
528 struct GNUNET_PSYC_CountersResultMessage res;
529 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
530 res.header.size = htons (sizeof (res));
531 res.result_code = htonl (result - INT32_MIN);
532 res.max_message_id = GNUNET_htonll (plc->max_message_id);
534 client_send_msg (plc, &res.header);
539 * Called when a PSYC master receives a join request.
542 psyc_recv_join_request (void *cls,
543 const struct GNUNET_PSYC_JoinRequestMessage *req,
544 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
545 const struct GNUNET_PSYC_Message *join_msg,
546 struct GNUNET_PSYC_JoinHandle *jh)
548 struct Host *hst = cls;
549 struct GNUNET_HashCode slave_key_hash;
550 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
551 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
552 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
553 client_send_msg (&hst->plc, &req->header);
558 * Called after a PSYC slave is connected.
561 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
563 struct Guest *gst = cls;
564 struct Place *plc = &gst->plc;
565 plc->max_message_id = max_message_id;
566 plc->is_ready = GNUNET_YES;
568 struct GNUNET_PSYC_CountersResultMessage res;
569 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
570 res.header.size = htons (sizeof (res));
571 res.result_code = htonl (result - INT32_MIN);
572 res.max_message_id = GNUNET_htonll (plc->max_message_id);
574 client_send_msg (plc, &res.header);
579 * Called when a PSYC slave receives a join decision.
582 psyc_recv_join_dcsn (void *cls,
583 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
585 const struct GNUNET_PSYC_Message *join_msg)
587 struct Guest *gst = cls;
588 client_send_msg (&gst->plc, &dcsn->header);
593 * Called when a PSYC master or slave receives a message.
596 psyc_recv_message (void *cls,
599 const struct GNUNET_PSYC_MessageHeader *msg)
601 struct Place *plc = cls;
603 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_key);
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605 "%p Received PSYC message of size %u from %s.\n",
606 plc, ntohs (msg->header.size), str);
609 client_send_msg (plc, &msg->header);
611 /* FIXME: further processing */
616 * Initialize place data structure.
619 place_init (struct Place *plc)
626 * Handle a connecting client entering a place as host.
629 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
630 const struct GNUNET_MessageHeader *msg)
632 const struct HostEnterRequest *req
633 = (const struct HostEnterRequest *) msg;
635 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
636 struct GNUNET_HashCode pub_key_hash;
638 GNUNET_CRYPTO_eddsa_key_get_public (&req->place_key, &pub_key);
639 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
642 hst = GNUNET_CONTAINER_multihashmap_get (hosts, &pub_key_hash);
647 hst = GNUNET_new (struct Host);
648 hst->policy = ntohl (req->policy);
649 hst->priv_key = req->place_key;
650 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
653 plc->is_host = GNUNET_YES;
654 plc->pub_key = pub_key;
655 plc->pub_key_hash = pub_key_hash;
658 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
659 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
660 hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy,
661 &psyc_master_started,
662 &psyc_recv_join_request,
663 &psyc_recv_message, NULL, hst);
664 hst->plc.channel = GNUNET_PSYC_master_get_channel (hst->master);
670 struct GNUNET_PSYC_CountersResultMessage res;
671 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
672 res.header.size = htons (sizeof (res));
673 res.result_code = htonl (GNUNET_OK);
674 res.max_message_id = GNUNET_htonll (plc->max_message_id);
676 GNUNET_SERVER_notification_context_add (nc, client);
677 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
681 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
682 "%p Client connected as host to place %s.\n",
683 hst, GNUNET_h2s (&plc->pub_key_hash));
685 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
686 cli->client = client;
687 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
689 struct Client *ctx = GNUNET_new (struct Client);
691 GNUNET_SERVER_client_set_user_context (client, ctx);
692 GNUNET_SERVER_receive_done (client, GNUNET_OK);
697 * Handle a connecting client entering a place as guest.
700 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
701 const struct GNUNET_MessageHeader *msg)
703 const struct GuestEnterRequest *req
704 = (const struct GuestEnterRequest *) msg;
705 uint16_t req_size = ntohs (req->header.size);
707 struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key;
708 struct GNUNET_HashCode pub_key_hash, gst_pub_key_hash;
710 GNUNET_CRYPTO_ecdsa_key_get_public (&req->guest_key, &gst_pub_key);
711 GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash);
712 GNUNET_CRYPTO_hash (&req->place_key, sizeof (req->place_key), &pub_key_hash);
714 struct GNUNET_CONTAINER_MultiHashMap *
715 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &pub_key_hash);
716 struct Guest *gst = NULL;
721 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash);
723 if (NULL == gst || NULL == gst->slave)
725 gst = GNUNET_new (struct Guest);
726 gst->priv_key = req->guest_key;
727 gst->pub_key = gst_pub_key;
728 gst->pub_key_hash = gst_pub_key_hash;
729 gst->origin = req->origin;
730 gst->relay_count = ntohl (req->relay_count);
732 const struct GNUNET_PeerIdentity *
733 relays = (const struct GNUNET_PeerIdentity *) &req[1];
734 uint16_t relay_size = gst->relay_count * sizeof (*relays);
735 struct GNUNET_PSYC_Message *join_msg = NULL;
736 uint16_t join_msg_size = 0;
738 if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader)
741 join_msg = (struct GNUNET_PSYC_Message *)
742 (((char *) &req[1]) + relay_size);
743 join_msg_size = ntohs (join_msg->header.size);
745 if (sizeof (*req) + relay_size + join_msg_size != req_size)
747 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
748 "%u + %u + %u != %u\n",
749 sizeof (*req), relay_size, join_msg_size, req_size);
751 GNUNET_SERVER_client_disconnect (client);
755 if (0 < gst->relay_count)
757 gst->relays = GNUNET_malloc (relay_size);
758 memcpy (gst->relays, &req[1], relay_size);
762 plc->is_host = GNUNET_NO;
763 plc->pub_key = req->place_key;
764 plc->pub_key_hash = pub_key_hash;
769 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
770 (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
771 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
773 (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, gst,
774 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
775 (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
776 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
778 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key,
779 &gst->origin, gst->relay_count, gst->relays,
780 &psyc_recv_message, NULL, &psyc_slave_connected,
781 &psyc_recv_join_dcsn, gst, join_msg);
782 gst->plc.channel = GNUNET_PSYC_slave_get_channel (gst->slave);
788 struct GNUNET_PSYC_CountersResultMessage res;
789 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
790 res.header.size = htons (sizeof (res));
791 res.result_code = htonl (GNUNET_OK);
792 res.max_message_id = GNUNET_htonll (plc->max_message_id);
794 GNUNET_SERVER_notification_context_add (nc, client);
795 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
797 if (NULL != gst->join_dcsn)
799 GNUNET_SERVER_notification_context_add (nc, client);
800 GNUNET_SERVER_notification_context_unicast (nc, client,
801 &gst->join_dcsn->header,
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807 "%p Client connected as guest to place %s.\n",
808 gst, GNUNET_h2s (&plc->pub_key_hash));
810 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
811 cli->client = client;
812 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
814 struct Client *ctx = GNUNET_new (struct Client);
816 GNUNET_SERVER_client_set_user_context (client, ctx);
817 GNUNET_SERVER_receive_done (client, GNUNET_OK);
821 struct JoinDecisionClosure
824 struct GNUNET_PSYC_Message *msg;
829 * Iterator callback for responding to join requests.
832 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
835 struct JoinDecisionClosure *jcls = cls;
836 struct GNUNET_PSYC_JoinHandle *jh = value;
838 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
844 * Handle an entry decision from a host client.
847 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
848 const struct GNUNET_MessageHeader *msg)
851 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
852 GNUNET_assert (NULL != ctx);
853 struct Place *plc = ctx->plc;
854 GNUNET_assert (GNUNET_YES == plc->is_host);
855 struct Host *hst = (struct Host *) plc;
857 struct GNUNET_PSYC_JoinDecisionMessage *
858 dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
859 struct JoinDecisionClosure jcls;
860 jcls.is_admitted = ntohl (dcsn->is_admitted);
862 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
863 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
866 struct GNUNET_HashCode slave_key_hash;
867 GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871 "%p Got join decision (%d) from client for place %s..\n",
872 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
874 "%p ..and slave %s.\n",
875 hst, GNUNET_h2s (&slave_key_hash));
877 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
878 &psyc_send_join_decision, &jcls);
879 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
880 GNUNET_SERVER_receive_done (client, GNUNET_OK);
885 * Send acknowledgement to a client.
887 * Sent after a message fragment has been passed on to multicast.
889 * @param plc The place struct for the client.
892 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
894 struct GNUNET_MessageHeader res;
895 res.size = htons (sizeof (res));
896 res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
898 GNUNET_SERVER_notification_context_add (nc, client);
899 GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO);
904 * Proceed to the next message part in the transmission queue.
907 * Place where the transmission is going on.
909 * Currently transmitted message.
911 * Currently transmitted message fragment.
913 * @return @a tmit_frag, or NULL if reached the end of fragment.
915 static struct FragmentTransmitQueue *
916 psyc_transmit_queue_next_part (struct Place *plc,
917 struct MessageTransmitQueue *tmit_msg,
918 struct FragmentTransmitQueue *tmit_frag)
920 uint16_t psize = ntohs (tmit_frag->next_part->size);
921 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
925 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
927 else /* Reached end of current fragment. */
929 if (NULL != tmit_frag->client)
930 send_message_ack (plc, tmit_frag->client);
931 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
932 GNUNET_free (tmit_frag);
940 * Proceed to next message in transmission queue.
943 * Place where the transmission is going on.
945 * Currently transmitted message.
947 * @return The next message in queue, or NULL if queue is empty.
949 static struct MessageTransmitQueue *
950 psyc_transmit_queue_next_msg (struct Place *plc,
951 struct MessageTransmitQueue *tmit_msg)
953 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
954 GNUNET_free (tmit_msg);
955 return plc->tmit_msgs_head;
960 * Callback for data transmission to PSYC.
963 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
965 struct Place *plc = cls;
966 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
967 GNUNET_assert (NULL != tmit_msg);
968 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
969 if (NULL == tmit_frag)
970 { /* Rest of the message have not arrived yet, pause transmission */
974 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
984 "%p psyc_transmit_notify_data()\n", plc);
985 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
987 uint16_t ptype = ntohs (pmsg->type);
988 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
993 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
994 if (*data_size < pdata_size)
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 "%p psyc_transmit_notify_data: sending %u bytes.\n",
1005 *data_size = pdata_size;
1006 memcpy (data, &pmsg[1], *data_size);
1010 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1015 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1017 ret = GNUNET_SYSERR;
1021 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1022 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
1024 ret = GNUNET_SYSERR;
1027 if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
1030 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1031 plc->is_disconnected = GNUNET_YES;
1032 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1033 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1038 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1039 if (NULL != tmit_frag)
1041 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1042 ptype = ntohs (pmsg->type);
1045 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1048 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1049 ret = GNUNET_SYSERR;
1054 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1055 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1056 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1060 if (NULL == tmit_msg->frags_head
1061 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1062 { /* Reached end of current message. */
1063 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1067 if (ret != GNUNET_NO)
1069 if (NULL != tmit_msg)
1071 psyc_transmit_message (plc);
1073 else if (GNUNET_YES == plc->is_disconnected)
1075 /* FIXME: handle partial message (when still in_transmit) */
1076 cleanup_place (plc);
1084 * Callback for modifier transmission to PSYC.
1087 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1088 uint8_t *oper, uint32_t *full_value_size)
1090 struct Place *plc = cls;
1091 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1092 GNUNET_assert (NULL != tmit_msg);
1093 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1094 if (NULL == tmit_frag)
1095 { /* Rest of the message have not arrived yet, pause transmission */
1099 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1103 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
1108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109 "%p psyc_transmit_notify_mod()\n", plc);
1110 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1112 uint16_t ptype = ntohs (pmsg->type);
1117 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1122 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
1123 ret = GNUNET_SYSERR;
1126 struct GNUNET_PSYC_MessageModifier *
1127 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
1128 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
1130 if (*data_size < mod_size)
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1138 *full_value_size = ntohl (pmod->value_size);
1140 *data_size = mod_size;
1141 memcpy (data, &pmod[1], mod_size);
1146 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1151 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
1152 ret = GNUNET_SYSERR;
1155 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
1156 if (*data_size < mod_size)
1158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1159 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
1166 *data_size = mod_size;
1167 memcpy (data, &pmsg[1], *data_size);
1172 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1173 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1174 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1181 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
1183 ret = GNUNET_SYSERR;
1186 if (GNUNET_SYSERR == ret)
1189 ret = GNUNET_SYSERR;
1190 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1191 plc->is_disconnected = GNUNET_YES;
1192 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1193 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1197 if (GNUNET_YES != ret)
1198 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1200 if (NULL == tmit_msg->frags_head
1201 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1202 { /* Reached end of current message. */
1203 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1210 * Callback for data transmission from a host to PSYC.
1213 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1215 int ret = psyc_transmit_notify_data (cls, data_size, data);
1217 if (GNUNET_NO != ret)
1219 struct Host *hst = cls;
1220 hst->tmit_handle = NULL;
1227 * Callback for the transmit functions of multicast.
1230 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1232 int ret = psyc_transmit_notify_data (cls, data_size, data);
1234 if (GNUNET_NO != ret)
1236 struct Guest *gst = cls;
1237 gst->tmit_handle = NULL;
1244 * Callback for modifier transmission from a host to PSYC.
1247 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1248 uint8_t *oper, uint32_t *full_value_size)
1250 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1251 oper, full_value_size);
1252 if (GNUNET_SYSERR == ret)
1254 struct Host *hst = cls;
1255 hst->tmit_handle = NULL;
1262 * Callback for modifier transmission from a guest to PSYC.
1265 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1266 uint8_t *oper, uint32_t *full_value_size)
1268 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1269 oper, full_value_size);
1270 if (GNUNET_SYSERR == ret)
1272 struct Guest *gst = cls;
1273 gst->tmit_handle = NULL;
1280 * Get method part of next message from transmission queue.
1283 * Next item in message transmission queue.
1285 * The message method is returned here.
1287 * @return #GNUNET_OK on success
1288 * #GNUNET_NO if there are no more messages in queue.
1289 * #GNUNET_SYSERR if the next message is malformed.
1292 psyc_transmit_queue_next_method (struct Place *plc,
1293 struct GNUNET_PSYC_MessageMethod **pmeth)
1295 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1296 if (NULL == tmit_msg)
1299 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1300 if (NULL == tmit_frag)
1306 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1308 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
1310 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1311 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
1312 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
1314 return GNUNET_SYSERR;
1317 uint16_t psize = ntohs (pmsg->size);
1318 *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1319 if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
1321 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1322 "%p psyc_transmit_queue_next_method: invalid method name.\n",
1323 plc, ntohs (pmsg->type));
1324 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1325 "%u <= %u || NUL != %u\n",
1326 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
1328 return GNUNET_SYSERR;
1331 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1337 * Transmit the next message in queue from the host to the PSYC channel.
1340 psyc_master_transmit_message (struct Host *hst)
1343 if (NULL == hst->tmit_handle)
1345 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1346 int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
1347 if (GNUNET_OK != ret)
1351 = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
1352 &host_transmit_notify_mod,
1353 &host_transmit_notify_data, hst,
1358 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
1365 * Transmit the next message in queue from a guest to the PSYC channel.
1368 psyc_slave_transmit_message (struct Guest *gst)
1370 if (NULL == gst->tmit_handle)
1372 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1373 int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
1374 if (GNUNET_OK != ret)
1378 = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
1379 &guest_transmit_notify_mod,
1380 &guest_transmit_notify_data, gst,
1385 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
1392 * Transmit a message to PSYC.
1395 psyc_transmit_message (struct Place *plc)
1399 ? psyc_master_transmit_message ((struct Host *) plc)
1400 : psyc_slave_transmit_message ((struct Guest *) plc);
1405 * Queue message parts for sending to PSYC.
1407 * @param plc Place to send to.
1408 * @param client Client the message originates from.
1409 * @param data_size Size of @a data.
1410 * @param data Concatenated message parts.
1411 * @param first_ptype First message part type in @a data.
1412 * @param last_ptype Last message part type in @a data.
1414 static struct MessageTransmitQueue *
1415 psyc_transmit_queue_message (struct Place *plc,
1416 struct GNUNET_SERVER_Client *client,
1419 uint16_t first_ptype, uint16_t last_ptype,
1420 struct MessageTransmitQueue *tmit_msg)
1422 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1424 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
1425 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1427 else if (NULL == tmit_msg)
1432 struct FragmentTransmitQueue *
1433 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
1434 memcpy (&tmit_frag[1], data, data_size);
1435 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
1436 tmit_frag->client = client;
1437 tmit_frag->size = data_size;
1439 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1440 tmit_msg->client = client;
1446 * Cancel transmission of current message to PSYC.
1448 * @param plc Place to send to.
1449 * @param client Client the message originates from.
1452 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
1454 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
1456 struct GNUNET_MessageHeader msg;
1457 msg.size = htons (sizeof (msg));
1458 msg.type = htons (type);
1460 psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
1461 psyc_transmit_message (plc);
1463 /* FIXME: cleanup */
1468 * Handle an incoming message from a client, to be transmitted to the place.
1471 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
1472 const struct GNUNET_MessageHeader *msg)
1475 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1476 GNUNET_assert (NULL != ctx);
1477 struct Place *plc = ctx->plc;
1478 int ret = GNUNET_SYSERR;
1480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1481 "%p Received message from client.\n", plc);
1482 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
1484 if (GNUNET_YES != plc->is_ready)
1486 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1487 "%p Place is not ready yet, disconnecting client.\n", plc);
1489 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1493 uint16_t size = ntohs (msg->size);
1494 uint16_t psize = size - sizeof (*msg);
1495 if (psize < sizeof (struct GNUNET_MessageHeader)
1496 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
1498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1499 "%p Received message with invalid payload size (%u) from client.\n",
1502 psyc_transmit_cancel (plc, client);
1503 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1507 uint16_t first_ptype = 0, last_ptype = 0;
1509 == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
1510 &first_ptype, &last_ptype))
1512 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1513 "%p Received invalid message part from client.\n", plc);
1515 psyc_transmit_cancel (plc, client);
1516 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "%p Received message with first part type %u and last part type %u.\n",
1521 plc, first_ptype, last_ptype);
1524 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
1525 first_ptype, last_ptype, ctx->tmit_msg);
1526 if (NULL != ctx->tmit_msg)
1528 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
1529 ctx->tmit_msg = NULL;
1530 ret = psyc_transmit_message (plc);
1533 if (GNUNET_OK != ret)
1535 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1536 "%p Received invalid message part from client.\n", plc);
1538 psyc_transmit_cancel (plc, client);
1539 ret = GNUNET_SYSERR;
1541 GNUNET_SERVER_receive_done (client, ret);
1546 * A historic message arrived from PSYC.
1549 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
1550 const struct GNUNET_PSYC_MessageHeader *msg)
1552 struct OperationClosure *opcls = cls;
1553 struct Place *plc = opcls->plc;
1555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1556 "%p Received historic message #%" PRId64 " (flags: %x)\n",
1557 plc, message_id, flags);
1559 uint16_t size = ntohs (msg->header.size);
1561 struct GNUNET_OperationResultMessage *
1562 res = GNUNET_malloc (sizeof (*res) + size);
1563 res->header.size = htons (sizeof (*res) + size);
1564 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
1565 res->op_id = opcls->op_id;
1566 res->result_code = GNUNET_htonll (GNUNET_OK);
1568 memcpy (&res[1], msg, size);
1570 /** @todo FIXME: send only to requesting client */
1571 client_send_msg (plc, &res->header);
1576 * Result of message history replay from PSYC.
1579 psyc_recv_history_result (void *cls, int64_t result,
1580 const void *err_msg, uint16_t err_msg_size)
1582 struct OperationClosure *opcls = cls;
1583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1584 "%p History replay #%" PRIu64 ": "
1585 "PSYCstore returned %" PRId64 " (%.*s)\n",
1586 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1588 // FIXME: place might have been destroyed
1589 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
1594 * Client requests channel history.
1597 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
1598 const struct GNUNET_MessageHeader *msg)
1601 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1602 GNUNET_assert (NULL != ctx);
1603 struct Place *plc = ctx->plc;
1605 const struct GNUNET_PSYC_HistoryRequestMessage *
1606 req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
1607 uint16_t size = ntohs (msg->size);
1608 const char *method_prefix = (const char *) &req[1];
1610 if (size < sizeof (*req) + 1
1611 || '\0' != method_prefix[size - sizeof (*req) - 1])
1613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1614 "%p History replay #%" PRIu64 ": "
1615 "invalid method prefix. size: %u < %u?\n",
1616 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
1618 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1622 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
1623 opcls->client = client;
1625 opcls->op_id = req->op_id;
1626 opcls->flags = ntohl (req->flags);
1628 if (0 == req->message_limit)
1629 GNUNET_PSYC_channel_history_replay (plc->channel,
1630 GNUNET_ntohll (req->start_message_id),
1631 GNUNET_ntohll (req->end_message_id),
1632 method_prefix, opcls->flags,
1633 &psyc_recv_history_message, NULL,
1634 &psyc_recv_history_result, opcls);
1636 GNUNET_PSYC_channel_history_replay_latest (plc->channel,
1637 GNUNET_ntohll (req->message_limit),
1638 method_prefix, opcls->flags,
1639 &psyc_recv_history_message, NULL,
1640 &psyc_recv_history_result, opcls);
1642 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1647 * A state variable part arrived from PSYC.
1650 psyc_recv_state_var (void *cls,
1651 const struct GNUNET_MessageHeader *mod,
1654 uint32_t value_size,
1655 uint32_t full_value_size)
1657 struct OperationClosure *opcls = cls;
1658 struct Place *plc = opcls->plc;
1660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1661 "%p Received state variable %s from PSYC\n",
1664 uint16_t size = ntohs (mod->size);
1666 struct GNUNET_OperationResultMessage *
1667 res = GNUNET_malloc (sizeof (*res) + size);
1668 res->header.size = htons (sizeof (*res) + size);
1669 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
1670 res->op_id = opcls->op_id;
1671 res->result_code = GNUNET_htonll (GNUNET_OK);
1673 memcpy (&res[1], mod, size);
1675 /** @todo FIXME: send only to requesting client */
1676 client_send_msg (plc, &res->header);
1681 * Result of retrieving state variable from PSYC.
1684 psyc_recv_state_result (void *cls, int64_t result,
1685 const void *err_msg, uint16_t err_msg_size)
1687 struct OperationClosure *opcls = cls;
1688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1689 "%p State get #%" PRIu64 ": "
1690 "PSYCstore returned %" PRId64 " (%.*s)\n",
1691 opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1693 // FIXME: place might have been destroyed
1694 client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
1699 * Client requests channel history.
1702 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
1703 const struct GNUNET_MessageHeader *msg)
1706 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1707 GNUNET_assert (NULL != ctx);
1708 struct Place *plc = ctx->plc;
1710 const struct GNUNET_PSYC_StateRequestMessage *
1711 req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
1712 uint16_t size = ntohs (msg->size);
1713 const char *name = (const char *) &req[1];
1715 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1716 "%p State get #%" PRIu64 ": %s\n",
1717 plc, GNUNET_ntohll (req->op_id), name);
1719 if (size < sizeof (*req) + 1
1720 || '\0' != name[size - sizeof (*req) - 1])
1722 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1723 "%p State get #%" PRIu64 ": "
1724 "invalid name. size: %u < %u?\n",
1725 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
1727 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1731 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
1732 opcls->client = client;
1734 opcls->op_id = req->op_id;
1736 switch (ntohs (msg->type))
1738 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
1739 GNUNET_PSYC_channel_state_get (plc->channel, name,
1740 psyc_recv_state_var,
1741 psyc_recv_state_result, opcls);
1744 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
1745 GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
1746 psyc_recv_state_var,
1747 psyc_recv_state_result, opcls);
1754 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1758 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1759 { &client_recv_host_enter, NULL,
1760 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
1762 { &client_recv_guest_enter, NULL,
1763 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
1765 { &client_recv_join_decision, NULL,
1766 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
1768 { &client_recv_psyc_message, NULL,
1769 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
1771 { &client_recv_history_replay, NULL,
1772 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
1774 { &client_recv_state_get, NULL,
1775 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
1777 { &client_recv_state_get, NULL,
1778 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
1780 { NULL, NULL, 0, 0 }
1785 * Initialize the PSYC service.
1787 * @param cls Closure.
1788 * @param server The initialized server.
1789 * @param c Configuration to use.
1792 run (void *cls, struct GNUNET_SERVER_Handle *server,
1793 const struct GNUNET_CONFIGURATION_Handle *c)
1796 stats = GNUNET_STATISTICS_create ("social", cfg);
1797 hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1798 guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1799 place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1800 nc = GNUNET_SERVER_notification_context_create (server, 1);
1801 GNUNET_SERVER_add_handlers (server, handlers);
1802 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1803 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1804 &shutdown_task, NULL);
1809 * The main function for the service.
1811 * @param argc number of arguments from the command line
1812 * @param argv command line arguments
1813 * @return 0 ok, 1 on error
1816 main (int argc, char *const *argv)
1818 return (GNUNET_OK ==
1819 GNUNET_SERVICE_run (argc, argv, "social",
1820 GNUNET_SERVICE_OPTION_NONE,
1821 &run, NULL)) ? 0 : 1;
1824 /* end of gnunet-service-social.c */