aace01fed9cf013a16554d26fe1a23b76afcb6b6
[oweals/gnunet.git] / src / social / gnunet-service-social.c
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2013 Christian Grothoff (and other contributing authors)
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /**
22  * @file social/gnunet-service-social.c
23  * @brief Social service
24  * @author Gabor X Toth
25  */
26
27 #include <inttypes.h>
28
29 #include "platform.h"
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"
37 #include "social.h"
38
39
40 /**
41  * Handle to our current configuration.
42  */
43 static const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45 /**
46  * Handle to the statistics service.
47  */
48 static struct GNUNET_STATISTICS_Handle *stats;
49
50 /**
51  * Notification context, simplifies client broadcasts.
52  */
53 static struct GNUNET_SERVER_NotificationContext *nc;
54
55 /**
56  * All connected hosts.
57  * H(place_pub_key) -> struct Host
58  */
59 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
60
61 /**
62  * All connected guests.
63  * H(place_pub_key) -> struct Guest
64  */
65 static struct GNUNET_CONTAINER_MultiHashMap *guests;
66
67 /**
68  * Connected guests per place.
69  * H(place_pub_key) -> Guest's pub_key -> struct Guest
70  */
71 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
72
73 /**
74  * Places entered as host or guest.
75  * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
76  */
77 static struct GNUNET_CONTAINER_MultiHashMap *places_entered;
78
79 /**
80  * Place listener clients.
81  * H(ego_pub_key) -> struct PlaceListener
82  */
83 static struct GNUNET_CONTAINER_MultiHashMap *place_listeners;
84
85 /**
86  * Directory for storing places.
87  */
88 static char *dir_places;
89
90
91 /**
92  * Message fragment transmission queue.
93  */
94 struct FragmentTransmitQueue
95 {
96   struct FragmentTransmitQueue *prev;
97   struct FragmentTransmitQueue *next;
98
99   struct GNUNET_SERVER_Client *client;
100
101   /**
102    * Pointer to the next message part inside the data after this struct.
103    */
104   struct GNUNET_MessageHeader *next_part;
105
106   /**
107    * Size of message.
108    */
109   uint16_t size;
110
111   /**
112    * @see enum GNUNET_PSYC_MessageState
113    */
114   uint8_t state;
115
116   /* Followed by one or more message parts. */
117 };
118
119
120 /**
121  * Message transmission queue.
122  */
123 struct MessageTransmitQueue
124 {
125   struct MessageTransmitQueue *prev;
126   struct MessageTransmitQueue *next;
127
128   struct FragmentTransmitQueue *frags_head;
129   struct FragmentTransmitQueue *frags_tail;
130
131   struct GNUNET_SERVER_Client *client;
132 };
133
134 /**
135  * List of connected clients.
136  */
137 struct ClientListItem
138 {
139   struct ClientListItem *prev;
140   struct ClientListItem *next;
141
142   struct GNUNET_SERVER_Client *client;
143 };
144
145
146 /**
147  * Common part of the client context for both a host and guest.
148  */
149 struct Place
150 {
151   struct ClientListItem *clients_head;
152   struct ClientListItem *clients_tail;
153
154   struct MessageTransmitQueue *tmit_msgs_head;
155   struct MessageTransmitQueue *tmit_msgs_tail;
156
157   struct GNUNET_PSYC_Channel *channel;
158
159   /**
160    * Public key of the channel.
161    */
162   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
163
164   /**
165    * Hash of @a pub_key.
166    */
167   struct GNUNET_HashCode pub_key_hash;
168
169   /**
170    * Last message ID received for the place.
171    * 0 if there is no such message.
172    */
173   uint64_t max_message_id;
174
175   /**
176    * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
177    */
178   uint8_t is_host;
179
180   /**
181    * Is this place ready to receive messages from client?
182    * #GNUNET_YES or #GNUNET_NO
183    */
184   uint8_t is_ready;
185
186   /**
187    * Is the client disconnected?
188    * #GNUNET_YES or #GNUNET_NO
189    */
190   uint8_t is_disconnected;
191 };
192
193
194 /**
195  * Client context for a host.
196  */
197 struct Host
198 {
199   /**
200    * Place struct common for Host and Guest
201    */
202   struct Place plc;
203
204   /**
205    * Private key of the channel.
206    */
207   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
208
209   /**
210    * Handle for the multicast origin.
211    */
212   struct GNUNET_PSYC_Master *master;
213
214   /**
215    * Transmit handle for multicast.
216    */
217   struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
218
219   /**
220    * Incoming join requests.
221    * guest_key -> struct GNUNET_PSYC_JoinHandle *
222    */
223   struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
224
225   /**
226    * @see enum GNUNET_PSYC_Policy
227    */
228   enum GNUNET_PSYC_Policy policy;
229 };
230
231
232 /**
233  * Client context for a guest.
234  */
235 struct Guest
236 {
237   /**
238    * Place struct common for Host and Guest.
239    */
240   struct Place plc;
241
242   /**
243    * Private key of the slave.
244    */
245   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
246
247   /**
248    * Public key of the slave.
249    */
250   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
251
252   /**
253    * Hash of @a pub_key.
254    */
255   struct GNUNET_HashCode pub_key_hash;
256
257   /**
258    * Handle for the PSYC slave.
259    */
260   struct GNUNET_PSYC_Slave *slave;
261
262   /**
263    * Transmit handle for multicast.
264    */
265   struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
266
267   /**
268    * Peer identity of the origin.
269    */
270   struct GNUNET_PeerIdentity origin;
271
272   /**
273    * Number of items in @a relays.
274    */
275   uint32_t relay_count;
276
277   /**
278    * Relays that multicast can use to connect.
279    */
280   struct GNUNET_PeerIdentity *relays;
281
282   /**
283    * Join request to be transmitted to the master on join.
284    */
285   struct GNUNET_MessageHeader *join_req;
286
287   /**
288    * Join decision received from PSYC.
289    */
290   struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
291
292 };
293
294
295 /**
296  * Context for host/guest client.
297  */
298 struct Client
299 {
300   /**
301    * Place where the client entered.
302    */
303   struct Place *plc;
304
305   /**
306    * Message queue for the message currently being transmitted
307    * by this client.
308    */
309   struct MessageTransmitQueue *tmit_msg;
310
311   /**
312    * Ego key for listener clients;
313    */
314   struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
315 };
316
317
318 struct PlaceListener
319 {
320   struct ClientListItem *clients_head;
321   struct ClientListItem *clients_tail;
322 };
323
324
325 struct OperationClosure
326 {
327   struct GNUNET_SERVER_Client *client;
328   struct Place *plc;
329   uint64_t op_id;
330   uint32_t flags;
331 };
332
333
334 static int
335 psyc_transmit_message (struct Place *plc);
336
337
338 /**
339  * Task run during shutdown.
340  *
341  * @param cls unused
342  * @param tc unused
343  */
344 static void
345 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
346 {
347   if (NULL != nc)
348   {
349     GNUNET_SERVER_notification_context_destroy (nc);
350     nc = NULL;
351   }
352   if (NULL != stats)
353   {
354     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
355     stats = NULL;
356   }
357 }
358
359
360 /**
361  * Clean up host data structures after a client disconnected.
362  */
363 static void
364 cleanup_host (struct Host *hst)
365 {
366   struct Place *plc = &hst->plc;
367
368   if (NULL != hst->master)
369     GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
370   GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
371   GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
372 }
373
374
375 /**
376  * Clean up guest data structures after a client disconnected.
377  */
378 static void
379 cleanup_guest (struct Guest *gst)
380 {
381   struct Place *plc = &gst->plc;
382   struct GNUNET_CONTAINER_MultiHashMap *
383     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
384                                                 &plc->pub_key_hash);
385   GNUNET_assert (NULL != plc_gst); // FIXME
386   GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst);
387
388   if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
389   {
390     GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
391                                           plc_gst);
392     GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
393   }
394   GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
395
396   if (NULL != gst->join_req)
397     GNUNET_free (gst->join_req);
398   if (NULL != gst->relays)
399     GNUNET_free (gst->relays);
400   if (NULL != gst->slave)
401     GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
402   GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
403 }
404
405
406 /**
407  * Clean up place data structures after a client disconnected.
408  */
409 static void
410 cleanup_place (struct Place *plc)
411 {
412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413               "%p Cleaning up place %s\n",
414               plc, GNUNET_h2s (&plc->pub_key_hash));
415
416   (GNUNET_YES == plc->is_host)
417     ? cleanup_host ((struct Host *) plc)
418     : cleanup_guest ((struct Guest *) plc);
419   GNUNET_free (plc);
420 }
421
422
423 static void
424 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
425 {
426   cleanup_place (cls);
427 }
428
429
430 /**
431  * Called whenever a client is disconnected.
432  * Frees our resources associated with that client.
433  *
434  * @param cls Closure.
435  * @param client Identification of the client.
436  */
437 static void
438 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
439 {
440   if (NULL == client)
441     return;
442
443   struct Client *
444     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
445   if (NULL == ctx)
446   {
447     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
448                 "%p User context is NULL in client_disconnect()\n", ctx);
449     GNUNET_break (0);
450     return;
451   }
452
453   struct Place *plc = ctx->plc;
454   if (NULL == plc)
455     return; // place listener client, nothing to do
456
457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458               "%p Client (%s) disconnected from place %s\n",
459               plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
460               GNUNET_h2s (&plc->pub_key_hash));
461
462   struct ClientListItem *cli = plc->clients_head;
463   while (NULL != cli)
464   {
465     if (cli->client == client)
466     {
467       GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
468       GNUNET_free (cli);
469       break;
470     }
471     cli = cli->next;
472   }
473
474   if (NULL == plc->clients_head)
475   { /* Last client disconnected. */
476     if (GNUNET_YES != plc->is_disconnected)
477     {
478       plc->is_disconnected = GNUNET_YES;
479       if (NULL != plc->tmit_msgs_head)
480       { /* Send pending messages to PSYC before cleanup. */
481         psyc_transmit_message (plc);
482       }
483       else
484       {
485         cleanup_place (plc);
486       }
487     }
488   }
489 }
490
491
492 /**
493  * Send message to all clients connected to the channel.
494  */
495 static void
496 client_send_msg (const struct Place *plc,
497                  const struct GNUNET_MessageHeader *msg)
498 {
499   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
500               "%p Sending message to clients.\n", plc);
501
502   struct ClientListItem *cli = plc->clients_head;
503   while (NULL != cli)
504   {
505     GNUNET_SERVER_notification_context_add (nc, cli->client);
506     GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, GNUNET_NO);
507     cli = cli->next;
508   }
509 }
510
511
512 /**
513  * Send a result code back to the client.
514  *
515  * @param client
516  *        Client that should receive the result code.
517  * @param result_code
518  *        Code to transmit.
519  * @param op_id
520  *        Operation ID in network byte order.
521  * @param data
522  *        Data payload or NULL.
523  * @param data_size
524  *        Size of @a data.
525  */
526 static void
527 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
528                     int64_t result_code, const void *data, uint16_t data_size)
529 {
530   struct GNUNET_OperationResultMessage *res;
531
532   res = GNUNET_malloc (sizeof (*res) + data_size);
533   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
534   res->header.size = htons (sizeof (*res) + data_size);
535   res->result_code = GNUNET_htonll (result_code);
536   res->op_id = op_id;
537   if (0 < data_size)
538     memcpy (&res[1], data, data_size);
539
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541               "%p Sending result to client for operation #%" PRIu64 ": "
542               "%" PRId64 " (size: %u)\n",
543               client, GNUNET_ntohll (op_id), result_code, data_size);
544
545   GNUNET_SERVER_notification_context_add (nc, client);
546   GNUNET_SERVER_notification_context_unicast (nc, client, &res->header,
547                                               GNUNET_NO);
548   GNUNET_free (res);
549 }
550
551
552 /**
553  * Called after a PSYC master is started.
554  */
555 static void
556 psyc_master_started (void *cls, int result, uint64_t max_message_id)
557 {
558   struct Host *hst = cls;
559   struct Place *plc = &hst->plc;
560   plc->max_message_id = max_message_id;
561   plc->is_ready = GNUNET_YES;
562
563   struct GNUNET_PSYC_CountersResultMessage res;
564   res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
565   res.header.size = htons (sizeof (res));
566   res.result_code = htonl (result);
567   res.max_message_id = GNUNET_htonll (plc->max_message_id);
568
569   client_send_msg (plc, &res.header);
570 }
571
572
573 /**
574  * Called when a PSYC master receives a join request.
575  */
576 static void
577 psyc_recv_join_request (void *cls,
578                         const struct GNUNET_PSYC_JoinRequestMessage *req,
579                         const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
580                         const struct GNUNET_PSYC_Message *join_msg,
581                         struct GNUNET_PSYC_JoinHandle *jh)
582 {
583   struct Host *hst = cls;
584   struct GNUNET_HashCode slave_key_hash;
585   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
586   GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
587                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
588   client_send_msg (&hst->plc, &req->header);
589 }
590
591
592 /**
593  * Called after a PSYC slave is connected.
594  */
595 static void
596 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
597 {
598   struct Guest *gst = cls;
599   struct Place *plc = &gst->plc;
600   plc->max_message_id = max_message_id;
601   plc->is_ready = GNUNET_YES;
602
603   struct GNUNET_PSYC_CountersResultMessage res;
604   res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
605   res.header.size = htons (sizeof (res));
606   res.result_code = htonl (result);
607   res.max_message_id = GNUNET_htonll (plc->max_message_id);
608
609   client_send_msg (plc, &res.header);
610 }
611
612
613 /**
614  * Called when a PSYC slave receives a join decision.
615  */
616 static void
617 psyc_recv_join_dcsn (void *cls,
618                      const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
619                      int is_admitted,
620                      const struct GNUNET_PSYC_Message *join_msg)
621 {
622   struct Guest *gst = cls;
623   client_send_msg (&gst->plc, &dcsn->header);
624 }
625
626
627 /**
628  * Called when a PSYC master or slave receives a message.
629  */
630 static void
631 psyc_recv_message (void *cls,
632                    uint64_t message_id,
633                    uint32_t flags,
634                    const struct GNUNET_PSYC_MessageHeader *msg)
635 {
636   struct Place *plc = cls;
637
638   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_key);
639   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640               "%p Received PSYC message of size %u from %s.\n",
641               plc, ntohs (msg->header.size), str);
642   GNUNET_free (str);
643
644   client_send_msg (plc, &msg->header);
645
646   /* FIXME: further processing */
647 }
648
649
650 /**
651  * Initialize place data structure.
652  */
653 static void
654 place_init (struct Place *plc)
655 {
656
657 }
658
659
660 /**
661  * Add place to places_entered hash map.
662  *
663  * @param ego_pub_hash
664  *        H(ego_pub_key)
665  * @param place_pub_hash
666  *        H(place_pub_key)
667  * @param msg
668  *        Entry message.
669  *
670  * @return Return value of GNUNET_CONTAINER_multihashmap_put ()
671  */
672 static int
673 place_add (const struct GNUNET_HashCode *ego_pub_hash,
674            const struct GNUNET_HashCode *place_pub_hash,
675            const struct GNUNET_MessageHeader *msg)
676 {
677   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678               "Adding place to hashmap:\n");
679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680               "  ego_pub_hash = %s\n", GNUNET_h2s (ego_pub_hash));
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "  place_pub_hash = %s\n", GNUNET_h2s (place_pub_hash));
683
684   struct GNUNET_CONTAINER_MultiHashMap *
685     ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, ego_pub_hash);
686   if (NULL == ego_places)
687   {
688     ego_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
689     GNUNET_CONTAINER_multihashmap_put (places_entered, ego_pub_hash, ego_places,
690                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
691   }
692
693   struct GNUNET_MessageHeader *msg_old, *msg_new;
694   if (NULL != (msg_old = GNUNET_CONTAINER_multihashmap_get (ego_places, place_pub_hash)))
695   {
696     GNUNET_free (msg_old);
697     GNUNET_CONTAINER_multihashmap_remove_all (ego_places, place_pub_hash);
698   }
699
700   uint16_t msg_size = ntohs (msg->size);
701   msg_new = GNUNET_malloc (msg_size);
702   memcpy (msg_new, msg, msg_size);
703   int ret = GNUNET_CONTAINER_multihashmap_put (ego_places, place_pub_hash, msg_new,
704                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
705   if (GNUNET_OK != ret)
706     GNUNET_break (0);
707   return ret;
708 }
709
710
711 /**
712  * Save place entry message to disk.
713  *
714  * @param ego_key
715  *        Private key of ego.
716  * @param place_pub_hash
717  *        Hash of public key of place.
718  * @param msg
719  *        Entry message.
720  */
721 static void
722 place_save (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_key,
723             const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub,
724             const struct GNUNET_MessageHeader *msg)
725 {
726   if (NULL == dir_places)
727     return;
728
729   struct GNUNET_HashCode place_pub_hash;
730   GNUNET_CRYPTO_hash (place_pub, sizeof (place_pub), &place_pub_hash);
731
732   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
733   struct GNUNET_HashCode ego_pub_hash;
734   GNUNET_CRYPTO_ecdsa_key_get_public (ego_key, &ego_pub);
735   GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
736
737   place_add (&ego_pub_hash, &place_pub_hash, msg);
738
739   char *ego_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
740   char *place_pub_hash_str = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
741   memcpy (ego_pub_hash_str, GNUNET_h2s_full (&ego_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
742   memcpy (place_pub_hash_str, GNUNET_h2s_full (&place_pub_hash), sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
743
744   char *filename = GNUNET_malloc (strlen (dir_places) + 1
745                                   + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1
746                                   + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1);
747   GNUNET_asprintf (&filename,
748                    "%s%s%s%s%s",
749                    dir_places, DIR_SEPARATOR_STR,
750                    ego_pub_hash_str, DIR_SEPARATOR_STR,
751                    place_pub_hash_str);
752
753   GNUNET_DISK_directory_create_for_file (filename);
754   if (GNUNET_DISK_fn_write (filename, msg, ntohs (msg->size),
755                             GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE) < 0)
756   {
757     GNUNET_break (0);
758   }
759
760   GNUNET_free (ego_pub_hash_str);
761   GNUNET_free (place_pub_hash_str);
762   GNUNET_free (filename);
763 }
764
765
766 /**
767  * Enter place as host.
768  *
769  * @param req
770  *        Entry request.
771  * @param[out] ret_hst
772  *        Returned Host struct.
773  *
774  * @return #GNUNET_YES if the host entered the place just now,
775  *         #GNUNET_NO  if the place is already entered.
776  */
777 static int
778 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
779 {
780   int ret = GNUNET_NO;
781   struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
782   struct GNUNET_HashCode place_pub_hash;
783
784   GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
785   GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
786
787   struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
788   if (NULL == hst)
789   {
790     hst = GNUNET_new (struct Host);
791     hst->policy = ntohl (hreq->policy);
792     hst->priv_key = hreq->place_key;
793     hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
794
795     struct Place *plc = &hst->plc;
796     plc->is_host = GNUNET_YES;
797     plc->pub_key = place_pub;
798     plc->pub_key_hash = place_pub_hash;
799     place_init (plc);
800
801     GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
802                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
803     hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy,
804                                             &psyc_master_started,
805                                             &psyc_recv_join_request,
806                                             &psyc_recv_message, NULL, hst);
807     hst->plc.channel = GNUNET_PSYC_master_get_channel (hst->master);
808     ret = GNUNET_YES;
809   }
810
811   if (NULL != ret_hst)
812     *ret_hst = hst;
813   return ret;
814 }
815
816
817 /**
818  * Handle a connecting client entering a place as host.
819  */
820 static void
821 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
822                         const struct GNUNET_MessageHeader *msg)
823 {
824   const struct HostEnterRequest *hreq
825     = (const struct HostEnterRequest *) msg;
826   struct Place *plc;
827   struct Host *hst;
828
829   switch (host_enter (hreq, &hst))
830   {
831   case GNUNET_YES:
832     plc = &hst->plc;
833     break;
834
835   case GNUNET_NO:
836   {
837     plc = &hst->plc;
838
839     struct GNUNET_PSYC_CountersResultMessage res;
840     res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
841     res.header.size = htons (sizeof (res));
842     res.result_code = htonl (GNUNET_OK);
843     res.max_message_id = GNUNET_htonll (plc->max_message_id);
844
845     GNUNET_SERVER_notification_context_add (nc, client);
846     GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
847                                                 GNUNET_NO);
848     break;
849   }
850   case GNUNET_SYSERR:
851     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
852     return;
853   }
854
855   struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
856   GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
857
858   place_save (&hreq->host_key, &place_pub, msg);
859
860   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
861               "%p Client connected as host to place %s.\n",
862               hst, GNUNET_h2s (&plc->pub_key_hash));
863
864   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
865   cli->client = client;
866   GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
867
868   struct Client *ctx = GNUNET_new (struct Client);
869   ctx->plc = plc;
870   GNUNET_SERVER_client_set_user_context (client, ctx);
871   GNUNET_SERVER_receive_done (client, GNUNET_OK);
872 }
873
874
875 /**
876  * Enter place as guest.
877  *
878  * @param req
879  *        Entry request.
880  * @param[out] ret_gst
881  *        Returned Guest struct.
882  *
883  * @return #GNUNET_YES if the guest entered the place just now,
884  *         #GNUNET_NO  if the place is already entered.
885  */
886 static int
887 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
888 {
889   int ret = GNUNET_NO;
890   uint16_t greq_size = ntohs (greq->header.size);
891
892   struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key;
893   struct GNUNET_HashCode place_pub_hash, gst_pub_key_hash;
894   GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &gst_pub_key);
895   GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash);
896   GNUNET_CRYPTO_hash (&greq->place_key, sizeof (greq->place_key), &place_pub_hash);
897
898   struct GNUNET_CONTAINER_MultiHashMap *
899     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
900   struct Guest *gst = NULL;
901   struct Place *plc;
902
903   if (NULL != plc_gst)
904     gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash);
905
906   if (NULL == gst || NULL == gst->slave)
907   {
908     gst = GNUNET_new (struct Guest);
909     gst->priv_key = greq->guest_key;
910     gst->pub_key = gst_pub_key;
911     gst->pub_key_hash = gst_pub_key_hash;
912     gst->origin = greq->origin;
913     gst->relay_count = ntohl (greq->relay_count);
914
915     const struct GNUNET_PeerIdentity *relays = NULL;
916     uint16_t relay_size = gst->relay_count * sizeof (*relays);
917     if (0 < relay_size)
918       relays = (const struct GNUNET_PeerIdentity *) &greq[1];
919     struct GNUNET_PSYC_Message *join_msg = NULL;
920     uint16_t join_msg_size = 0;
921
922     if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader)
923         <= greq_size)
924     {
925       join_msg = (struct GNUNET_PSYC_Message *)
926         (((char *) &greq[1]) + relay_size);
927       join_msg_size = ntohs (join_msg->header.size);
928     }
929     if (sizeof (*greq) + relay_size + join_msg_size != greq_size)
930     {
931       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
932                   "%u + %u + %u != %u\n",
933                   sizeof (*greq), relay_size, join_msg_size, greq_size);
934       GNUNET_break (0);
935       GNUNET_free (gst);
936       return GNUNET_SYSERR;
937     }
938     if (0 < gst->relay_count)
939     {
940       gst->relays = GNUNET_malloc (relay_size);
941       memcpy (gst->relays, &greq[1], relay_size);
942     }
943
944     plc = &gst->plc;
945     plc->is_host = GNUNET_NO;
946     plc->pub_key = greq->place_key;
947     plc->pub_key_hash = place_pub_hash;
948     place_init (plc);
949
950     if (NULL == plc_gst)
951     {
952       plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
953       (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
954                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
955     }
956     (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, gst,
957                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
958     (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
959                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
960     gst->slave
961       = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key,
962                                 &gst->origin, gst->relay_count, gst->relays,
963                                 &psyc_recv_message, NULL, &psyc_slave_connected,
964                                 &psyc_recv_join_dcsn, gst, join_msg);
965     gst->plc.channel = GNUNET_PSYC_slave_get_channel (gst->slave);
966     ret = GNUNET_YES;
967   }
968
969   if (NULL != ret_gst)
970     *ret_gst = gst;
971   return ret;
972 }
973
974
975 /**
976  * Handle a connecting client entering a place as guest.
977  */
978 static void
979 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
980                          const struct GNUNET_MessageHeader *msg)
981 {
982   const struct GuestEnterRequest *
983     greq = (const struct GuestEnterRequest *) msg;
984   struct Guest *gst = NULL;
985   struct Place *plc = NULL;
986
987   switch (guest_enter (greq, &gst))
988   {
989   case GNUNET_YES:
990     plc = &gst->plc;
991     break;
992
993   case GNUNET_NO:
994   {
995     plc = &gst->plc;
996
997     struct GNUNET_PSYC_CountersResultMessage res;
998     res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
999     res.header.size = htons (sizeof (res));
1000     res.result_code = htonl (GNUNET_OK);
1001     res.max_message_id = GNUNET_htonll (plc->max_message_id);
1002
1003     GNUNET_SERVER_notification_context_add (nc, client);
1004     GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
1005                                                 GNUNET_NO);
1006     if (NULL != gst->join_dcsn)
1007     {
1008       GNUNET_SERVER_notification_context_add (nc, client);
1009       GNUNET_SERVER_notification_context_unicast (nc, client,
1010                                                   &gst->join_dcsn->header,
1011                                                   GNUNET_NO);
1012     }
1013     break;
1014   }
1015   case GNUNET_SYSERR:
1016     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1017     return;
1018   }
1019
1020   place_save (&greq->guest_key, &greq->place_key, msg);
1021
1022   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1023               "%p Client connected as guest to place %s.\n",
1024               gst, GNUNET_h2s (&gst->plc.pub_key_hash));
1025
1026   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1027   cli->client = client;
1028   GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1029
1030   struct Client *ctx = GNUNET_new (struct Client);
1031   ctx->plc = plc;
1032   GNUNET_SERVER_client_set_user_context (client, ctx);
1033   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1034 }
1035
1036
1037 void
1038 place_notify (struct GNUNET_MessageHeader *msg,
1039               struct GNUNET_SERVER_Client *client)
1040 {
1041   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042               "%p Sending place notification of type %u to client.\n",
1043               client, ntohs (msg->type));
1044
1045  uint16_t msg_size = ntohs (msg->size);
1046   struct GNUNET_CRYPTO_EcdsaPublicKey place_pub;
1047
1048   switch (ntohs (msg->type))
1049   {
1050   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1051     if (msg_size < sizeof (struct HostEnterRequest))
1052       return;
1053     struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1054     GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &place_pub);
1055     break;
1056
1057   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1058     if (msg_size < sizeof (struct GuestEnterRequest))
1059       return;
1060     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1061     GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &place_pub);
1062     break;
1063
1064   default:
1065     return;
1066   }
1067
1068   GNUNET_SERVER_notification_context_add (nc, client);
1069   GNUNET_SERVER_notification_context_unicast (nc, client, msg,
1070                                               GNUNET_NO);
1071 }
1072
1073
1074 int
1075 map_entry_place (void *cls, const struct GNUNET_HashCode *key, void *value)
1076 {
1077   place_notify (value, cls);
1078   return GNUNET_YES;
1079 }
1080
1081
1082 /**
1083  * Handle a connecting client listening for entered places.
1084  */
1085 static void
1086 client_recv_place_listen (void *cls, struct GNUNET_SERVER_Client *client,
1087                           const struct GNUNET_MessageHeader *msg)
1088 {
1089   const struct PlaceListenRequest *req
1090     = (const struct PlaceListenRequest *) msg;
1091
1092   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
1093   struct GNUNET_HashCode ego_pub_hash;
1094
1095   GNUNET_CRYPTO_ecdsa_key_get_public (&req->ego_key, &ego_pub);
1096   GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
1097
1098   struct GNUNET_CONTAINER_MultiHashMap *
1099     ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, &ego_pub_hash);
1100   if (NULL != ego_places)
1101     GNUNET_CONTAINER_multihashmap_iterate (ego_places, map_entry_place, client);
1102
1103   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1104               "%p Client connected to listen for entered places of ego %s.\n",
1105               NULL, GNUNET_h2s (&ego_pub_hash));
1106
1107   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1108   cli->client = client;
1109   struct PlaceListener *pl = GNUNET_CONTAINER_multihashmap_get (place_listeners,
1110                                                                 &ego_pub_hash);
1111   if (NULL == pl) {
1112     pl = GNUNET_malloc (sizeof (*pl));
1113     (void) GNUNET_CONTAINER_multihashmap_put (place_listeners, &ego_pub_hash, pl,
1114                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1115   }
1116   GNUNET_CONTAINER_DLL_insert (pl->clients_head, pl->clients_tail, cli);
1117
1118   struct Client *ctx = GNUNET_new (struct Client);
1119   ctx->ego_key = req->ego_key;
1120   GNUNET_SERVER_client_set_user_context (client, ctx);
1121   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1122 }
1123
1124
1125 struct JoinDecisionClosure
1126 {
1127   int32_t is_admitted;
1128   struct GNUNET_PSYC_Message *msg;
1129 };
1130
1131
1132 /**
1133  * Iterator callback for responding to join requests.
1134  */
1135 static int
1136 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1137                          void *value)
1138 {
1139   struct JoinDecisionClosure *jcls = cls;
1140   struct GNUNET_PSYC_JoinHandle *jh = value;
1141   // FIXME: add relays
1142   GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1143   return GNUNET_YES;
1144 }
1145
1146
1147 /**
1148  * Handle an entry decision from a host client.
1149  */
1150 static void
1151 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
1152                            const struct GNUNET_MessageHeader *msg)
1153 {
1154   struct Client *
1155     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1156   GNUNET_assert (NULL != ctx);
1157   struct Place *plc = ctx->plc;
1158   GNUNET_assert (GNUNET_YES == plc->is_host);
1159   struct Host *hst = (struct Host *) plc;
1160
1161   struct GNUNET_PSYC_JoinDecisionMessage *
1162     dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
1163   struct JoinDecisionClosure jcls;
1164   jcls.is_admitted = ntohl (dcsn->is_admitted);
1165   jcls.msg
1166     = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
1167     ? (struct GNUNET_PSYC_Message *) &dcsn[1]
1168     : NULL;
1169
1170   struct GNUNET_HashCode slave_key_hash;
1171   GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
1172                       &slave_key_hash);
1173
1174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1175               "%p Got join decision (%d) from client for place %s..\n",
1176               hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
1177   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178               "%p ..and slave %s.\n",
1179               hst, GNUNET_h2s (&slave_key_hash));
1180
1181   GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
1182                                               &psyc_send_join_decision, &jcls);
1183   GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
1184   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1185 }
1186
1187
1188 /**
1189  * Send acknowledgement to a client.
1190  *
1191  * Sent after a message fragment has been passed on to multicast.
1192  *
1193  * @param plc The place struct for the client.
1194  */
1195 static void
1196 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
1197 {
1198   struct GNUNET_MessageHeader res;
1199   res.size = htons (sizeof (res));
1200   res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
1201
1202   GNUNET_SERVER_notification_context_add (nc, client);
1203   GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO);
1204 }
1205
1206
1207 /**
1208  * Proceed to the next message part in the transmission queue.
1209  *
1210  * @param plc
1211  *        Place where the transmission is going on.
1212  * @param tmit_msg
1213  *        Currently transmitted message.
1214  * @param tmit_frag
1215  *        Currently transmitted message fragment.
1216  *
1217  * @return @a tmit_frag, or NULL if reached the end of fragment.
1218  */
1219 static struct FragmentTransmitQueue *
1220 psyc_transmit_queue_next_part (struct Place *plc,
1221                                struct MessageTransmitQueue *tmit_msg,
1222                                struct FragmentTransmitQueue *tmit_frag)
1223 {
1224   uint16_t psize = ntohs (tmit_frag->next_part->size);
1225   if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
1226       < tmit_frag->size)
1227   {
1228     tmit_frag->next_part
1229       = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
1230   }
1231   else /* Reached end of current fragment. */
1232   {
1233     if (NULL != tmit_frag->client)
1234       send_message_ack (plc, tmit_frag->client);
1235     GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1236     GNUNET_free (tmit_frag);
1237     tmit_frag = NULL;
1238   }
1239   return tmit_frag;
1240 }
1241
1242
1243 /**
1244  * Proceed to next message in transmission queue.
1245  *
1246  * @param plc
1247  *        Place where the transmission is going on.
1248  * @param tmit_msg
1249  *        Currently transmitted message.
1250  *
1251  * @return The next message in queue, or NULL if queue is empty.
1252  */
1253 static struct MessageTransmitQueue *
1254 psyc_transmit_queue_next_msg (struct Place *plc,
1255                               struct MessageTransmitQueue *tmit_msg)
1256 {
1257   GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1258   GNUNET_free (tmit_msg);
1259   return plc->tmit_msgs_head;
1260 }
1261
1262
1263 /**
1264  * Callback for data transmission to PSYC.
1265  */
1266 static int
1267 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1268 {
1269   struct Place *plc = cls;
1270   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1271   GNUNET_assert (NULL != tmit_msg);
1272   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1273   if (NULL == tmit_frag)
1274   { /* Rest of the message have not arrived yet, pause transmission */
1275     *data_size = 0;
1276     return GNUNET_NO;
1277   }
1278   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1279   if (NULL == pmsg)
1280   {
1281     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1282                 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
1283     *data_size = 0;
1284     return GNUNET_NO;
1285   }
1286
1287   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288               "%p psyc_transmit_notify_data()\n", plc);
1289   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1290
1291   uint16_t ptype = ntohs (pmsg->type);
1292   uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
1293   int ret;
1294
1295   switch (ptype)
1296   {
1297   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1298     if (*data_size < pdata_size)
1299     {
1300       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301                 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
1302       *data_size = 0;
1303       return GNUNET_NO;
1304     }
1305     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306                 "%p psyc_transmit_notify_data: sending %u bytes.\n",
1307                 plc, pdata_size);
1308
1309     *data_size = pdata_size;
1310     memcpy (data, &pmsg[1], *data_size);
1311     ret = GNUNET_NO;
1312     break;
1313
1314   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1315     *data_size = 0;
1316     ret = GNUNET_YES;
1317     break;
1318
1319   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1320     *data_size = 0;
1321     ret = GNUNET_SYSERR;
1322     break;
1323
1324   default:
1325     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1326                 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
1327                 plc, ptype);
1328     ret = GNUNET_SYSERR;
1329   }
1330
1331   if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
1332   {
1333     *data_size = 0;
1334     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1335     plc->is_disconnected = GNUNET_YES;
1336     GNUNET_SERVER_client_disconnect (tmit_frag->client);
1337     GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1338     return ret;
1339   }
1340   else
1341   {
1342     tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1343     if (NULL != tmit_frag)
1344     {
1345       struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1346       ptype = ntohs (pmsg->type);
1347       switch (ptype)
1348       {
1349       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1350         ret = GNUNET_YES;
1351         break;
1352       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1353         ret = GNUNET_SYSERR;
1354         break;
1355       }
1356       switch (ptype)
1357       {
1358       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1359       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1360         tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1361       }
1362     }
1363
1364     if (NULL == tmit_msg->frags_head
1365         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1366     { /* Reached end of current message. */
1367       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1368     }
1369   }
1370
1371   if (ret != GNUNET_NO)
1372   {
1373     if (NULL != tmit_msg)
1374     {
1375       psyc_transmit_message (plc);
1376     }
1377     else if (GNUNET_YES == plc->is_disconnected)
1378     {
1379       /* FIXME: handle partial message (when still in_transmit) */
1380       cleanup_place (plc);
1381     }
1382   }
1383   return ret;
1384 }
1385
1386
1387 /**
1388  * Callback for modifier transmission to PSYC.
1389  */
1390 static int
1391 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1392                           uint8_t *oper, uint32_t *full_value_size)
1393 {
1394   struct Place *plc = cls;
1395   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1396   GNUNET_assert (NULL != tmit_msg);
1397   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1398   if (NULL == tmit_frag)
1399   { /* Rest of the message have not arrived yet, pause transmission */
1400     *data_size = 0;
1401     return GNUNET_NO;
1402   }
1403   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1404   if (NULL == pmsg)
1405   {
1406     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407                 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
1408     *data_size = 0;
1409     return GNUNET_NO;
1410   }
1411
1412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413               "%p psyc_transmit_notify_mod()\n", plc);
1414   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1415
1416   uint16_t ptype = ntohs (pmsg->type);
1417   int ret;
1418
1419   switch (ptype)
1420   {
1421   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1422   {
1423     if (NULL == oper)
1424     {
1425       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1426                   "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
1427       ret = GNUNET_SYSERR;
1428       break;
1429     }
1430     struct GNUNET_PSYC_MessageModifier *
1431       pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
1432     uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
1433
1434     if (*data_size < mod_size)
1435     {
1436       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1438       *data_size = 0;
1439       return GNUNET_NO;
1440     }
1441
1442     *full_value_size = ntohl (pmod->value_size);
1443     *oper = pmod->oper;
1444     *data_size = mod_size;
1445     memcpy (data, &pmod[1], mod_size);
1446     ret = GNUNET_NO;
1447     break;
1448   }
1449
1450   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1451   {
1452     if (NULL != oper)
1453     {
1454       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1455                   "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
1456       ret = GNUNET_SYSERR;
1457       break;
1458     }
1459     uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
1460     if (*data_size < mod_size)
1461     {
1462       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1464       *data_size = 0;
1465       return GNUNET_NO;
1466     }
1467     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1468                 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
1469
1470     *data_size = mod_size;
1471     memcpy (data, &pmsg[1], *data_size);
1472     ret = GNUNET_NO;
1473     break;
1474   }
1475
1476   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1477   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1478   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1479     *data_size = 0;
1480     ret = GNUNET_YES;
1481     break;
1482
1483   default:
1484     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1485                 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
1486                 plc, ptype);
1487     ret = GNUNET_SYSERR;
1488   }
1489
1490   if (GNUNET_SYSERR == ret)
1491   {
1492     *data_size = 0;
1493     ret = GNUNET_SYSERR;
1494     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1495     plc->is_disconnected = GNUNET_YES;
1496     GNUNET_SERVER_client_disconnect (tmit_frag->client);
1497     GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1498   }
1499   else
1500   {
1501     if (GNUNET_YES != ret)
1502       psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1503
1504     if (NULL == tmit_msg->frags_head
1505         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1506     { /* Reached end of current message. */
1507       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1508     }
1509   }
1510   return ret;
1511 }
1512
1513 /**
1514  * Callback for data transmission from a host to PSYC.
1515  */
1516 static int
1517 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1518 {
1519   int ret = psyc_transmit_notify_data (cls, data_size, data);
1520
1521   if (GNUNET_NO != ret)
1522   {
1523     struct Host *hst = cls;
1524     hst->tmit_handle = NULL;
1525   }
1526   return ret;
1527 }
1528
1529
1530 /**
1531  * Callback for the transmit functions of multicast.
1532  */
1533 static int
1534 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1535 {
1536   int ret = psyc_transmit_notify_data (cls, data_size, data);
1537
1538   if (GNUNET_NO != ret)
1539   {
1540     struct Guest *gst = cls;
1541     gst->tmit_handle = NULL;
1542   }
1543   return ret;
1544 }
1545
1546
1547 /**
1548  * Callback for modifier transmission from a host to PSYC.
1549  */
1550 static int
1551 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1552                           uint8_t *oper, uint32_t *full_value_size)
1553 {
1554   int ret = psyc_transmit_notify_mod (cls, data_size, data,
1555                                       oper, full_value_size);
1556   if (GNUNET_SYSERR == ret)
1557   {
1558     struct Host *hst = cls;
1559     hst->tmit_handle = NULL;
1560   }
1561   return ret;
1562 }
1563
1564
1565 /**
1566  * Callback for modifier transmission from a guest to PSYC.
1567  */
1568 static int
1569 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1570                            uint8_t *oper, uint32_t *full_value_size)
1571 {
1572   int ret = psyc_transmit_notify_mod (cls, data_size, data,
1573                                       oper, full_value_size);
1574   if (GNUNET_SYSERR == ret)
1575   {
1576     struct Guest *gst = cls;
1577     gst->tmit_handle = NULL;
1578   }
1579   return ret;
1580 }
1581
1582
1583 /**
1584  * Get method part of next message from transmission queue.
1585  *
1586  * @param tmit_msg
1587  *        Next item in message transmission queue.
1588  * @param[out] pmeth
1589  *        The message method is returned here.
1590  *
1591  * @return #GNUNET_OK on success
1592  *         #GNUNET_NO if there are no more messages in queue.
1593  *         #GNUNET_SYSERR if the next message is malformed.
1594  */
1595 static int
1596 psyc_transmit_queue_next_method (struct Place *plc,
1597                                  struct GNUNET_PSYC_MessageMethod **pmeth)
1598 {
1599   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1600   if (NULL == tmit_msg)
1601     return GNUNET_NO;
1602
1603   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1604   if (NULL == tmit_frag)
1605   {
1606     GNUNET_break (0);
1607     return GNUNET_NO;
1608   }
1609
1610   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1611   if (NULL == pmsg
1612       || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
1613   {
1614     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1615                 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
1616                 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
1617     GNUNET_break (0);
1618     return GNUNET_SYSERR;
1619   }
1620
1621   uint16_t psize = ntohs (pmsg->size);
1622   *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1623   if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
1624   {
1625     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1626                 "%p psyc_transmit_queue_next_method: invalid method name.\n",
1627                 plc, ntohs (pmsg->type));
1628     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1629                 "%u <= %u || NUL != %u\n",
1630                 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
1631     GNUNET_break (0);
1632     return GNUNET_SYSERR;
1633   }
1634
1635   psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1636   return GNUNET_OK;
1637 }
1638
1639
1640 /**
1641  * Transmit the next message in queue from the host to the PSYC channel.
1642  */
1643 static int
1644 psyc_master_transmit_message (struct Host *hst)
1645 {
1646
1647   if (NULL == hst->tmit_handle)
1648   {
1649     struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1650     int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
1651     if (GNUNET_OK != ret)
1652       return ret;
1653
1654     hst->tmit_handle
1655       = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
1656                                      &host_transmit_notify_mod,
1657                                      &host_transmit_notify_data, hst,
1658                                      pmeth->flags);
1659   }
1660   else
1661   {
1662     GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
1663   }
1664   return GNUNET_OK;
1665 }
1666
1667
1668 /**
1669  * Transmit the next message in queue from a guest to the PSYC channel.
1670  */
1671 static int
1672 psyc_slave_transmit_message (struct Guest *gst)
1673 {
1674   if (NULL == gst->tmit_handle)
1675   {
1676     struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1677     int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
1678     if (GNUNET_OK != ret)
1679       return ret;
1680
1681     gst->tmit_handle
1682       = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
1683                                     &guest_transmit_notify_mod,
1684                                     &guest_transmit_notify_data, gst,
1685                                     pmeth->flags);
1686   }
1687   else
1688   {
1689     GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
1690   }
1691   return GNUNET_OK;
1692 }
1693
1694
1695 /**
1696  * Transmit a message to PSYC.
1697  */
1698 static int
1699 psyc_transmit_message (struct Place *plc)
1700 {
1701   return
1702     (plc->is_host)
1703     ? psyc_master_transmit_message ((struct Host *) plc)
1704     : psyc_slave_transmit_message ((struct Guest *) plc);
1705 }
1706
1707
1708 /**
1709  * Queue message parts for sending to PSYC.
1710  *
1711  * @param plc          Place to send to.
1712  * @param client       Client the message originates from.
1713  * @param data_size    Size of @a data.
1714  * @param data         Concatenated message parts.
1715  * @param first_ptype  First message part type in @a data.
1716  * @param last_ptype   Last message part type in @a data.
1717  */
1718 static struct MessageTransmitQueue *
1719 psyc_transmit_queue_message (struct Place *plc,
1720                              struct GNUNET_SERVER_Client *client,
1721                              size_t data_size,
1722                              const void *data,
1723                              uint16_t first_ptype, uint16_t last_ptype,
1724                              struct MessageTransmitQueue *tmit_msg)
1725 {
1726   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1727   {
1728     tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
1729     GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1730   }
1731   else if (NULL == tmit_msg)
1732   {
1733     return NULL;
1734   }
1735
1736   struct FragmentTransmitQueue *
1737     tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
1738   memcpy (&tmit_frag[1], data, data_size);
1739   tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
1740   tmit_frag->client = client;
1741   tmit_frag->size = data_size;
1742
1743   GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1744   tmit_msg->client = client;
1745   return tmit_msg;
1746 }
1747
1748
1749 /**
1750  * Cancel transmission of current message to PSYC.
1751  *
1752  * @param plc     Place to send to.
1753  * @param client  Client the message originates from.
1754  */
1755 static void
1756 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
1757 {
1758   uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
1759
1760   struct GNUNET_MessageHeader msg;
1761   msg.size = htons (sizeof (msg));
1762   msg.type = htons (type);
1763
1764   psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
1765   psyc_transmit_message (plc);
1766
1767   /* FIXME: cleanup */
1768 }
1769
1770
1771 /**
1772  * Handle an incoming message from a client, to be transmitted to the place.
1773  */
1774 static void
1775 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
1776                           const struct GNUNET_MessageHeader *msg)
1777 {
1778   struct Client *
1779     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1780   GNUNET_assert (NULL != ctx);
1781   struct Place *plc = ctx->plc;
1782   int ret = GNUNET_SYSERR;
1783
1784   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785               "%p Received message from client.\n", plc);
1786   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
1787
1788   if (GNUNET_YES != plc->is_ready)
1789   {
1790     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1791                 "%p Place is not ready yet, disconnecting client.\n", plc);
1792     GNUNET_break (0);
1793     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1794     return;
1795   }
1796
1797   uint16_t size = ntohs (msg->size);
1798   uint16_t psize = size - sizeof (*msg);
1799   if (psize < sizeof (struct GNUNET_MessageHeader)
1800       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
1801   {
1802     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1803                 "%p Received message with invalid payload size (%u) from client.\n",
1804                 plc, psize);
1805     GNUNET_break (0);
1806     psyc_transmit_cancel (plc, client);
1807     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1808     return;
1809   }
1810
1811   uint16_t first_ptype = 0, last_ptype = 0;
1812   if (GNUNET_SYSERR
1813       == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
1814                                           &first_ptype, &last_ptype))
1815   {
1816     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1817                 "%p Received invalid message part from client.\n", plc);
1818     GNUNET_break (0);
1819     psyc_transmit_cancel (plc, client);
1820     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1821     return;
1822   }
1823   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824               "%p Received message with first part type %u and last part type %u.\n",
1825               plc, first_ptype, last_ptype);
1826
1827   ctx->tmit_msg
1828     = psyc_transmit_queue_message (plc, client, psize, &msg[1],
1829                                    first_ptype, last_ptype, ctx->tmit_msg);
1830   if (NULL != ctx->tmit_msg)
1831   {
1832     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
1833       ctx->tmit_msg = NULL;
1834     ret = psyc_transmit_message (plc);
1835   }
1836
1837   if (GNUNET_OK != ret)
1838   {
1839     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1840                 "%p Received invalid message part from client.\n", plc);
1841     GNUNET_break (0);
1842     psyc_transmit_cancel (plc, client);
1843     ret = GNUNET_SYSERR;
1844   }
1845   GNUNET_SERVER_receive_done (client, ret);
1846 }
1847
1848
1849 /**
1850  * A historic message arrived from PSYC.
1851  */
1852 static void
1853 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
1854                            const struct GNUNET_PSYC_MessageHeader *msg)
1855 {
1856   struct OperationClosure *opcls = cls;
1857   struct Place *plc = opcls->plc;
1858
1859   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860               "%p Received historic message #%" PRId64 " (flags: %x)\n",
1861               plc, message_id, flags);
1862
1863   uint16_t size = ntohs (msg->header.size);
1864
1865   struct GNUNET_OperationResultMessage *
1866     res = GNUNET_malloc (sizeof (*res) + size);
1867   res->header.size = htons (sizeof (*res) + size);
1868   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
1869   res->op_id = opcls->op_id;
1870   res->result_code = GNUNET_htonll (GNUNET_OK);
1871
1872   memcpy (&res[1], msg, size);
1873
1874   /** @todo FIXME: send only to requesting client */
1875   client_send_msg (plc, &res->header);
1876 }
1877
1878
1879 /**
1880  * Result of message history replay from PSYC.
1881  */
1882 static void
1883 psyc_recv_history_result (void *cls, int64_t result,
1884                           const void *err_msg, uint16_t err_msg_size)
1885 {
1886   struct OperationClosure *opcls = cls;
1887   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888               "%p History replay #%" PRIu64 ": "
1889               "PSYCstore returned %" PRId64 " (%.*s)\n",
1890               opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1891
1892   // FIXME: place might have been destroyed
1893   client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
1894 }
1895
1896
1897 /**
1898  * Client requests channel history.
1899  */
1900 static void
1901 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
1902                             const struct GNUNET_MessageHeader *msg)
1903 {
1904   struct Client *
1905     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1906   GNUNET_assert (NULL != ctx);
1907   struct Place *plc = ctx->plc;
1908
1909   const struct GNUNET_PSYC_HistoryRequestMessage *
1910     req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
1911   uint16_t size = ntohs (msg->size);
1912   const char *method_prefix = (const char *) &req[1];
1913
1914   if (size < sizeof (*req) + 1
1915       || '\0' != method_prefix[size - sizeof (*req) - 1])
1916   {
1917     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1918                 "%p History replay #%" PRIu64 ": "
1919                 "invalid method prefix. size: %u < %u?\n",
1920                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
1921     GNUNET_break (0);
1922     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1923     return;
1924   }
1925
1926   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
1927   opcls->client = client;
1928   opcls->plc = plc;
1929   opcls->op_id = req->op_id;
1930   opcls->flags = ntohl (req->flags);
1931
1932   if (0 == req->message_limit)
1933     GNUNET_PSYC_channel_history_replay (plc->channel,
1934                                         GNUNET_ntohll (req->start_message_id),
1935                                         GNUNET_ntohll (req->end_message_id),
1936                                         method_prefix, opcls->flags,
1937                                         &psyc_recv_history_message, NULL,
1938                                         &psyc_recv_history_result, opcls);
1939   else
1940     GNUNET_PSYC_channel_history_replay_latest (plc->channel,
1941                                                GNUNET_ntohll (req->message_limit),
1942                                                method_prefix, opcls->flags,
1943                                                &psyc_recv_history_message, NULL,
1944                                                &psyc_recv_history_result, opcls);
1945
1946   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1947 }
1948
1949
1950 /**
1951  * A state variable part arrived from PSYC.
1952  */
1953 void
1954 psyc_recv_state_var (void *cls,
1955                      const struct GNUNET_MessageHeader *mod,
1956                      const char *name,
1957                      const void *value,
1958                      uint32_t value_size,
1959                      uint32_t full_value_size)
1960 {
1961   struct OperationClosure *opcls = cls;
1962   struct Place *plc = opcls->plc;
1963
1964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1965               "%p Received state variable %s from PSYC\n",
1966               plc, name);
1967
1968   uint16_t size = ntohs (mod->size);
1969
1970   struct GNUNET_OperationResultMessage *
1971     res = GNUNET_malloc (sizeof (*res) + size);
1972   res->header.size = htons (sizeof (*res) + size);
1973   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
1974   res->op_id = opcls->op_id;
1975   res->result_code = GNUNET_htonll (GNUNET_OK);
1976
1977   memcpy (&res[1], mod, size);
1978
1979   /** @todo FIXME: send only to requesting client */
1980   client_send_msg (plc, &res->header);
1981 }
1982
1983
1984 /**
1985  * Result of retrieving state variable from PSYC.
1986  */
1987 static void
1988 psyc_recv_state_result (void *cls, int64_t result,
1989                         const void *err_msg, uint16_t err_msg_size)
1990 {
1991   struct OperationClosure *opcls = cls;
1992   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1993               "%p State get #%" PRIu64 ": "
1994               "PSYCstore returned %" PRId64 " (%.*s)\n",
1995               opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
1996
1997   // FIXME: place might have been destroyed
1998   client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
1999 }
2000
2001
2002 /**
2003  * Client requests channel history.
2004  */
2005 static void
2006 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
2007                        const struct GNUNET_MessageHeader *msg)
2008 {
2009   struct Client *
2010     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2011   GNUNET_assert (NULL != ctx);
2012   struct Place *plc = ctx->plc;
2013
2014   const struct GNUNET_PSYC_StateRequestMessage *
2015     req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
2016   uint16_t size = ntohs (msg->size);
2017   const char *name = (const char *) &req[1];
2018
2019   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2020               "%p State get #%" PRIu64 ": %s\n",
2021               plc, GNUNET_ntohll (req->op_id), name);
2022
2023   if (size < sizeof (*req) + 1
2024       || '\0' != name[size - sizeof (*req) - 1])
2025   {
2026     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2027                 "%p State get #%" PRIu64 ": "
2028                 "invalid name. size: %u < %u?\n",
2029                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2030     GNUNET_break (0);
2031     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2032     return;
2033   }
2034
2035   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2036   opcls->client = client;
2037   opcls->plc = plc;
2038   opcls->op_id = req->op_id;
2039
2040   switch (ntohs (msg->type))
2041   {
2042   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
2043       GNUNET_PSYC_channel_state_get (plc->channel, name,
2044                                      psyc_recv_state_var,
2045                                      psyc_recv_state_result, opcls);
2046       break;
2047
2048   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
2049       GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
2050                                             psyc_recv_state_var,
2051                                             psyc_recv_state_result, opcls);
2052       break;
2053
2054   default:
2055       GNUNET_assert (0);
2056   }
2057
2058   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2059 }
2060
2061
2062 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2063   { &client_recv_host_enter, NULL,
2064     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
2065
2066   { &client_recv_guest_enter, NULL,
2067     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
2068
2069   { &client_recv_join_decision, NULL,
2070     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
2071
2072   { &client_recv_psyc_message, NULL,
2073     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
2074
2075   { &client_recv_history_replay, NULL,
2076     GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
2077
2078   { &client_recv_state_get, NULL,
2079     GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
2080
2081   { &client_recv_state_get, NULL,
2082     GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
2083
2084   { &client_recv_place_listen, NULL,
2085     GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN, 0 },
2086
2087   { NULL, NULL, 0, 0 }
2088 };
2089
2090
2091 int
2092 file_place_load (void *cls, const char *filename)
2093 {
2094   uint64_t fsize = 0;
2095   if (GNUNET_OK !=
2096       GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES, GNUNET_YES)
2097       || fsize < sizeof (struct HostEnterRequest))
2098     return GNUNET_OK;
2099
2100   struct GNUNET_MessageHeader *msg = GNUNET_malloc (fsize);
2101   ssize_t rsize = GNUNET_DISK_fn_read (filename, msg, fsize);
2102   if (rsize < 0 || (size_t) rsize < sizeof (*msg))
2103     return GNUNET_OK;
2104
2105   uint16_t msg_size = ntohs (msg->size);
2106   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
2107   struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
2108
2109   switch (ntohs (msg->type))
2110   {
2111   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
2112     if (msg_size < sizeof (struct HostEnterRequest))
2113       return GNUNET_OK;
2114     struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
2115     GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &ego_pub);
2116     GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
2117
2118     host_enter (hreq, NULL);
2119     break;
2120
2121   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
2122     if (msg_size < sizeof (struct GuestEnterRequest))
2123       return GNUNET_OK;
2124     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
2125     GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &ego_pub);
2126     place_pub = greq->place_key;
2127
2128     guest_enter (greq, NULL);
2129     break;
2130
2131   default:
2132     return GNUNET_OK;
2133   }
2134
2135   struct GNUNET_HashCode ego_pub_hash, place_pub_hash;
2136   GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
2137   GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
2138
2139   place_add (&ego_pub_hash, &place_pub_hash, msg);
2140   return GNUNET_OK;
2141 }
2142
2143
2144 int
2145 load_places_of_ego (void *cls, const char *dir_ego)
2146 {
2147   if (GNUNET_YES != GNUNET_DISK_directory_test (dir_ego, GNUNET_YES))
2148     return GNUNET_OK;
2149
2150   GNUNET_DISK_directory_scan (dir_ego, file_place_load, NULL);
2151   return GNUNET_OK;
2152 }
2153
2154
2155 void
2156 load_places ()
2157 {
2158   if (GNUNET_OK !=
2159       GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "PLACES_DIR",
2160                                                &dir_places))
2161   {
2162     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "social", "PLACES_DIR");
2163     GNUNET_break (0);
2164     return;
2165   }
2166
2167   places_entered = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
2168   GNUNET_DISK_directory_scan (dir_places, load_places_of_ego, NULL);
2169 }
2170
2171
2172 /**
2173  * Initialize the PSYC service.
2174  *
2175  * @param cls Closure.
2176  * @param server The initialized server.
2177  * @param c Configuration to use.
2178  */
2179 static void
2180 run (void *cls, struct GNUNET_SERVER_Handle *server,
2181      const struct GNUNET_CONFIGURATION_Handle *c)
2182 {
2183   cfg = c;
2184   stats = GNUNET_STATISTICS_create ("social", cfg);
2185   hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2186   guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2187   place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2188   place_listeners = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2189   load_places ();
2190
2191   nc = GNUNET_SERVER_notification_context_create (server, 1);
2192   GNUNET_SERVER_add_handlers (server, handlers);
2193   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
2194   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2195                                 &shutdown_task, NULL);
2196 }
2197
2198
2199 /**
2200  * The main function for the service.
2201  *
2202  * @param argc number of arguments from the command line
2203  * @param argv command line arguments
2204  * @return 0 ok, 1 on error
2205  */
2206 int
2207 main (int argc, char *const *argv)
2208 {
2209   return (GNUNET_OK ==
2210           GNUNET_SERVICE_run (argc, argv, "social",
2211                               GNUNET_SERVICE_OPTION_NONE,
2212                               &run, NULL)) ? 0 : 1;
2213 }
2214
2215 /* end of gnunet-service-social.c */