social: API changes for application connections: store/load app subscriptions to...
[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 #include <strings.h>
29
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_core_service.h"
35 #include "gnunet_identity_service.h"
36 #include "gnunet_namestore_service.h"
37 #include "gnunet_gns_service.h"
38 #include "gnunet_statistics_service.h"
39 #include "gnunet_psyc_service.h"
40 #include "gnunet_psyc_util_lib.h"
41 #include "gnunet_social_service.h"
42 #include "social.h"
43
44
45 /**
46  * Handle to our current configuration.
47  */
48 static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50 /* Handles to other services */
51 static struct GNUNET_CORE_Handle *core;
52 static struct GNUNET_IDENTITY_Handle *id;
53 static struct GNUNET_GNS_Handle *gns;
54 static struct GNUNET_NAMESTORE_Handle *namestore;
55 static struct GNUNET_STATISTICS_Handle *stats;
56
57 /**
58  * ID of this peer.
59  */
60 static struct GNUNET_PeerIdentity this_peer;
61
62 /**
63  * Notification context, simplifies client broadcasts.
64  */
65 static struct GNUNET_SERVER_NotificationContext *nc;
66
67 /**
68  * All connected hosts.
69  * H(place_pub_key) -> struct Host
70  */
71 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
72
73 /**
74  * All connected guests.
75  * H(place_pub_key) -> struct Guest
76  */
77 static struct GNUNET_CONTAINER_MultiHashMap *guests;
78
79 /**
80  * Connected guests per place.
81  * H(place_pub_key) -> ego_pub_key -> struct Guest
82  */
83 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
84
85 /**
86  * Places entered as host or guest.
87  * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
88  */
89 static struct GNUNET_CONTAINER_MultiHashMap *places;
90
91 /**
92  * Places entered per application.
93  * H(app_id) -> H(place_pub_key) -> NULL
94  */
95 static struct GNUNET_CONTAINER_MultiHashMap *apps_places;
96
97 /**
98  * Connected applications.
99  * H(app_id) -> struct Application
100  */
101 static struct GNUNET_CONTAINER_MultiHashMap *apps;
102
103 /**
104  * All egos.
105  * H(ego_pub_key) -> struct Ego
106  */
107 static struct GNUNET_CONTAINER_MultiHashMap *egos;
108
109 /**
110  * Directory for storing social data.
111  * Default: ~/.local/share/gnunet/social
112  */
113 static char *dir_social;
114
115 /**
116  * Directory for storing place data.
117  * $dir_social/places
118  */
119 static char *dir_places;
120
121 /**
122  * Directory for storing app data.
123  * $dir_social/apps
124  */
125 static char *dir_apps;
126
127
128 /**
129  * Message fragment transmission queue.
130  */
131 struct FragmentTransmitQueue
132 {
133   struct FragmentTransmitQueue *prev;
134   struct FragmentTransmitQueue *next;
135
136   struct GNUNET_SERVER_Client *client;
137
138   /**
139    * Pointer to the next message part inside the data after this struct.
140    */
141   struct GNUNET_MessageHeader *next_part;
142
143   /**
144    * Size of message.
145    */
146   uint16_t size;
147
148   /**
149    * @see enum GNUNET_PSYC_MessageState
150    */
151   uint8_t state;
152
153   /* Followed by one or more message parts. */
154 };
155
156
157 /**
158  * Message transmission queue.
159  */
160 struct MessageTransmitQueue
161 {
162   struct MessageTransmitQueue *prev;
163   struct MessageTransmitQueue *next;
164
165   struct FragmentTransmitQueue *frags_head;
166   struct FragmentTransmitQueue *frags_tail;
167
168   struct GNUNET_SERVER_Client *client;
169 };
170
171 /**
172  * List of connected clients.
173  */
174 struct ClientListItem
175 {
176   struct ClientListItem *prev;
177   struct ClientListItem *next;
178
179   struct GNUNET_SERVER_Client *client;
180 };
181
182
183 /**
184  * Common part of the client context for both a host and guest.
185  */
186 struct Place
187 {
188   struct ClientListItem *clients_head;
189   struct ClientListItem *clients_tail;
190
191   struct MessageTransmitQueue *tmit_msgs_head;
192   struct MessageTransmitQueue *tmit_msgs_tail;
193
194   struct GNUNET_PSYC_Channel *channel;
195
196   /**
197    * Private key of home in case of a host.
198    */
199   struct GNUNET_CRYPTO_EddsaPublicKey key;
200
201   /**
202    * Public key of place.
203    */
204   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
205
206   /**
207    * Hash of @a pub_key.
208    */
209   struct GNUNET_HashCode pub_key_hash;
210
211   /**
212    * Private key of ego.
213    */
214   struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
215
216   /**
217    * Public key of ego.
218    */
219   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
220
221   /**
222    * Hash of @a ego_pub_key.
223    */
224   struct GNUNET_HashCode ego_pub_hash;
225
226   /**
227    * Last message ID received for the place.
228    * 0 if there is no such message.
229    */
230   uint64_t max_message_id;
231
232   /**
233    * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
234    */
235   uint8_t is_host;
236
237   /**
238    * Is this place ready to receive messages from client?
239    * #GNUNET_YES or #GNUNET_NO
240    */
241   uint8_t is_ready;
242
243   /**
244    * Is the client disconnected?
245    * #GNUNET_YES or #GNUNET_NO
246    */
247   uint8_t is_disconnected;
248 };
249
250
251 /**
252  * Client context for a host.
253  */
254 struct Host
255 {
256   /**
257    * Place struct common for Host and Guest
258    */
259   struct Place plc;
260
261   /**
262    * Handle for the multicast origin.
263    */
264   struct GNUNET_PSYC_Master *master;
265
266   /**
267    * Transmit handle for multicast.
268    */
269   struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
270
271   /**
272    * Incoming join requests.
273    * guest_key -> struct GNUNET_PSYC_JoinHandle *
274    */
275   struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
276
277   /**
278    * @see enum GNUNET_PSYC_Policy
279    */
280   enum GNUNET_PSYC_Policy policy;
281 };
282
283
284 /**
285  * Client context for a guest.
286  */
287 struct Guest
288 {
289   /**
290    * Place struct common for Host and Guest.
291    */
292   struct Place plc;
293
294   /**
295    * Handle for the PSYC slave.
296    */
297   struct GNUNET_PSYC_Slave *slave;
298
299   /**
300    * Transmit handle for multicast.
301    */
302   struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
303
304   /**
305    * Peer identity of the origin.
306    */
307   struct GNUNET_PeerIdentity origin;
308
309   /**
310    * Number of items in @a relays.
311    */
312   uint32_t relay_count;
313
314   /**
315    * Relays that multicast can use to connect.
316    */
317   struct GNUNET_PeerIdentity *relays;
318
319   /**
320    * Join request to be transmitted to the master on join.
321    */
322   struct GNUNET_MessageHeader *join_req;
323
324   /**
325    * Join decision received from PSYC.
326    */
327   struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
328
329 };
330
331
332 /**
333  * Context for a client.
334  */
335 struct Client
336 {
337   /**
338    * Place where the client entered.
339    */
340   struct Place *plc;
341
342   /**
343    * Message queue for the message currently being transmitted
344    * by this client.
345    */
346   struct MessageTransmitQueue *tmit_msg;
347
348   /**
349    * ID for application clients.
350    */
351   char *app_id;
352 };
353
354
355 struct Application
356 {
357   struct ClientListItem *clients_head;
358   struct ClientListItem *clients_tail;
359 };
360
361
362 struct Ego {
363   struct GNUNET_CRYPTO_EcdsaPrivateKey key;
364   char *name;
365 };
366
367
368 struct OperationClosure
369 {
370   struct GNUNET_SERVER_Client *client;
371   struct Place *plc;
372   uint64_t op_id;
373   uint32_t flags;
374 };
375
376
377 static int
378 psyc_transmit_message (struct Place *plc);
379
380
381 static void
382 cleanup_place (struct Place *plc);
383
384
385 int
386 place_entry_cleanup (void *cls, const struct GNUNET_HashCode *key, void *value)
387 {
388   cleanup_place (value);
389   return GNUNET_YES;
390 }
391
392
393 /**
394  * Task run during shutdown.
395  *
396  * @param cls unused
397  * @param tc unused
398  */
399 static void
400 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
401 {
402   GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL);
403   GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL);
404
405   if (NULL != nc)
406   {
407     GNUNET_SERVER_notification_context_destroy (nc);
408     nc = NULL;
409   }
410   if (NULL != core)
411   {
412     GNUNET_CORE_disconnect (core);
413     core = NULL;
414   }
415   if (NULL != id)
416   {
417     GNUNET_IDENTITY_disconnect (id);
418     id = NULL;
419   }
420   if (NULL != namestore)
421   {
422     GNUNET_NAMESTORE_disconnect (namestore);
423     namestore = NULL;
424   }
425   if (NULL != gns)
426   {
427     GNUNET_GNS_disconnect (gns);
428     gns = NULL;
429   }
430   if (NULL != stats)
431   {
432     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
433     stats = NULL;
434   }
435 }
436
437
438 /**
439  * Clean up host data structures after a client disconnected.
440  */
441 static void
442 cleanup_host (struct Host *hst)
443 {
444   struct Place *plc = &hst->plc;
445
446   if (NULL != hst->master)
447     GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
448   GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
449   GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
450 }
451
452
453 /**
454  * Clean up guest data structures after a client disconnected.
455  */
456 static void
457 cleanup_guest (struct Guest *gst)
458 {
459   struct Place *plc = &gst->plc;
460   struct GNUNET_CONTAINER_MultiHashMap *
461     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
462                                                 &plc->pub_key_hash);
463   GNUNET_assert (NULL != plc_gst); // FIXME
464   GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst);
465
466   if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
467   {
468     GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
469                                           plc_gst);
470     GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
471   }
472   GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
473
474   if (NULL != gst->join_req)
475     GNUNET_free (gst->join_req);
476   if (NULL != gst->relays)
477     GNUNET_free (gst->relays);
478   if (NULL != gst->slave)
479     GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
480   GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
481 }
482
483
484 /**
485  * Clean up place data structures after a client disconnected.
486  */
487 static void
488 cleanup_place (struct Place *plc)
489 {
490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
491               "%p Cleaning up place %s\n",
492               plc, GNUNET_h2s (&plc->pub_key_hash));
493
494   (GNUNET_YES == plc->is_host)
495     ? cleanup_host ((struct Host *) plc)
496     : cleanup_guest ((struct Guest *) plc);
497   GNUNET_free (plc);
498 }
499
500
501 static void
502 schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
503 {
504   cleanup_place (cls);
505 }
506
507
508 /**
509  * Called whenever a client is disconnected.
510  * Frees our resources associated with that client.
511  *
512  * @param cls Closure.
513  * @param client Identification of the client.
514  */
515 static void
516 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
517 {
518   if (NULL == client)
519     return;
520
521   struct Client *
522     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
523   if (NULL == ctx)
524   {
525     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526                 "%p User context is NULL in client_disconnect()\n", ctx);
527     return;
528   }
529
530   struct Place *plc = ctx->plc;
531
532   if (NULL != ctx->app_id)
533     GNUNET_free (ctx->app_id);
534
535   GNUNET_free (ctx);
536
537   if (NULL == plc)
538     return; // application client, nothing to do
539
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541               "%p Client (%s) disconnected from place %s\n",
542               plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
543               GNUNET_h2s (&plc->pub_key_hash));
544
545   struct ClientListItem *cli = plc->clients_head;
546   while (NULL != cli)
547   {
548     if (cli->client == client)
549     {
550       GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
551       GNUNET_free (cli);
552       break;
553     }
554     cli = cli->next;
555   }
556 }
557
558
559 /**
560  * Send message to a client.
561  */
562 static inline void
563 client_send_msg (struct GNUNET_SERVER_Client *client,
564                  const struct GNUNET_MessageHeader *msg)
565 {
566   GNUNET_SERVER_notification_context_add (nc, client);
567   GNUNET_SERVER_notification_context_unicast (nc, client, msg, GNUNET_NO);
568 }
569
570
571 /**
572  * Send message to all clients connected to a place.
573  */
574 static void
575 place_send_msg (const struct Place *plc,
576                  const struct GNUNET_MessageHeader *msg)
577 {
578   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579               "%p Sending message to clients of place.\n", plc);
580
581   struct ClientListItem *cli = plc->clients_head;
582   while (NULL != cli)
583   {
584     client_send_msg (cli->client, msg);
585     cli = cli->next;
586   }
587 }
588
589
590 /**
591  * Send a result code back to the client.
592  *
593  * @param client
594  *        Client that should receive the result code.
595  * @param result_code
596  *        Code to transmit.
597  * @param op_id
598  *        Operation ID in network byte order.
599  * @param data
600  *        Data payload or NULL.
601  * @param data_size
602  *        Size of @a data.
603  */
604 static void
605 client_send_result (struct GNUNET_SERVER_Client *client, uint64_t op_id,
606                     int64_t result_code, const void *data, uint16_t data_size)
607 {
608   struct GNUNET_OperationResultMessage *res;
609
610   res = GNUNET_malloc (sizeof (*res) + data_size);
611   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
612   res->header.size = htons (sizeof (*res) + data_size);
613   res->result_code = GNUNET_htonll (result_code);
614   res->op_id = op_id;
615   if (0 < data_size)
616     memcpy (&res[1], data, data_size);
617
618   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619               "%p Sending result to client for operation #%" PRIu64 ": "
620               "%" PRId64 " (size: %u)\n",
621               client, GNUNET_ntohll (op_id), result_code, data_size);
622
623   client_send_msg (client, &res->header);
624   GNUNET_free (res);
625 }
626
627
628 static void
629 client_send_host_enter_ack (struct GNUNET_SERVER_Client *client,
630                             struct Host *hst, uint32_t result)
631 {
632   struct Place *plc = &hst->plc;
633
634   struct HostEnterAck hack;
635   hack.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
636   hack.header.size = htons (sizeof (hack));
637   hack.result_code = htonl (result);
638   hack.max_message_id = GNUNET_htonll (plc->max_message_id);
639   hack.place_pub_key = plc->pub_key;
640
641   if (NULL != client)
642     client_send_msg (client, &hack.header);
643   else
644     place_send_msg (plc, &hack.header);
645 }
646
647
648 /**
649  * Called after a PSYC master is started.
650  */
651 static void
652 psyc_master_started (void *cls, int result, uint64_t max_message_id)
653 {
654   struct Host *hst = cls;
655   struct Place *plc = &hst->plc;
656   plc->max_message_id = max_message_id;
657   plc->is_ready = GNUNET_YES;
658
659   client_send_host_enter_ack (NULL, hst, result);
660 }
661
662
663 /**
664  * Called when a PSYC master receives a join request.
665  */
666 static void
667 psyc_recv_join_request (void *cls,
668                         const struct GNUNET_PSYC_JoinRequestMessage *req,
669                         const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
670                         const struct GNUNET_PSYC_Message *join_msg,
671                         struct GNUNET_PSYC_JoinHandle *jh)
672 {
673   struct Host *hst = cls;
674   struct GNUNET_HashCode slave_key_hash;
675   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
676   GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
677                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
678   place_send_msg (&hst->plc, &req->header);
679 }
680
681
682 /**
683  * Called after a PSYC slave is connected.
684  */
685 static void
686 psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
687 {
688   struct Guest *gst = cls;
689   struct Place *plc = &gst->plc;
690   plc->max_message_id = max_message_id;
691   plc->is_ready = GNUNET_YES;
692
693   struct GNUNET_PSYC_CountersResultMessage res;
694   res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
695   res.header.size = htons (sizeof (res));
696   res.result_code = htonl (result);
697   res.max_message_id = GNUNET_htonll (plc->max_message_id);
698
699   place_send_msg (plc, &res.header);
700 }
701
702
703 /**
704  * Called when a PSYC slave receives a join decision.
705  */
706 static void
707 psyc_recv_join_dcsn (void *cls,
708                      const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
709                      int is_admitted,
710                      const struct GNUNET_PSYC_Message *join_msg)
711 {
712   struct Guest *gst = cls;
713   place_send_msg (&gst->plc, &dcsn->header);
714 }
715
716
717 /**
718  * Called when a PSYC master or slave receives a message.
719  */
720 static void
721 psyc_recv_message (void *cls,
722                    uint64_t message_id,
723                    uint32_t flags,
724                    const struct GNUNET_PSYC_MessageHeader *msg)
725 {
726   struct Place *plc = cls;
727
728   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_key);
729   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730               "%p Received PSYC message of size %u from %s.\n",
731               plc, ntohs (msg->header.size), str);
732   GNUNET_free (str);
733
734   place_send_msg (plc, &msg->header);
735
736   /* FIXME: further processing */
737 }
738
739
740 /**
741  * Initialize place data structure.
742  */
743 static void
744 place_init (struct Place *plc)
745 {
746
747 }
748
749 /**
750  * Add a place to the @e places hash map.
751  *
752  * @param ereq
753  *        Entry request.
754  *
755  * @return #GNUNET_OK if the place was added
756  *         #GNUNET_NO if the place already exists in the hash map
757  *         #GNUNET_SYSERR on error
758  */
759 static int
760 place_add (const struct PlaceEnterRequest *ereq)
761 {
762   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763               "Adding place to hashmap:\n");
764
765   struct EgoPlacePublicKey ego_place_pub_key = {
766     .ego_pub_key = ereq->ego_pub_key,
767     .place_pub_key = ereq->place_pub_key,
768   };
769   struct GNUNET_HashCode ego_place_pub_hash;
770   GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
771
772   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
773               "  ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
774
775   struct GNUNET_MessageHeader *
776     place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash);
777   if (NULL != place_msg)
778     return GNUNET_NO;
779
780   place_msg = GNUNET_copy_message (&ereq->header);
781   if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg,
782                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
783   {
784     GNUNET_break (0);
785     GNUNET_free (place_msg);
786     return GNUNET_SYSERR;
787   }
788
789   return GNUNET_OK;
790 }
791
792 /**
793  * Add a place to the @e app_places hash map.
794  *
795  * @param app_id
796  *        Application ID.
797  * @param msg
798  *        Entry message.
799  *
800  * @return #GNUNET_OK if the place was added
801  *         #GNUNET_NO if the place already exists in the hash map
802  *         #GNUNET_SYSERR on error
803  */
804 static int
805 app_place_add (const char *app_id,
806                const struct PlaceEnterRequest *ereq)
807 {
808   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809               "Adding app place to hashmap:\n");
810   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811               "  app_id = %s\n", app_id);
812
813   struct GNUNET_HashCode app_id_hash;
814   GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
815
816   struct EgoPlacePublicKey ego_place_pub_key = {
817     .ego_pub_key = ereq->ego_pub_key,
818     .place_pub_key = ereq->place_pub_key,
819   };
820   struct GNUNET_HashCode ego_place_pub_hash;
821   GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
822
823   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
824               "  ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
825
826   struct GNUNET_CONTAINER_MultiHashMap *
827     app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
828   if (NULL == app_places)
829   {
830     app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
831     GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places,
832                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
833   }
834
835   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash))
836     return GNUNET_NO;
837
838   if (GNUNET_SYSERR == place_add (ereq))
839     return GNUNET_SYSERR;
840
841   if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash,
842                                                       NULL, 0))
843   {
844     GNUNET_break (0);
845     return GNUNET_SYSERR;
846   }
847
848   return GNUNET_OK;
849 }
850
851
852 /**
853  * Save place entry message to disk.
854  *
855  * @param app_id
856  *        Application ID.
857  * @param msg
858  *        Entry message.
859  */
860 static int
861 app_place_save (const char *app_id,
862                 const struct PlaceEnterRequest *ereq)
863 {
864   app_place_add (app_id, ereq);
865
866   if (NULL == dir_places)
867     return GNUNET_SYSERR;
868
869   struct GNUNET_HashCode ego_pub_hash;
870   struct GNUNET_HashCode place_pub_hash;
871   GNUNET_CRYPTO_hash (&ereq->ego_pub_key, sizeof (ereq->ego_pub_key),
872                       &ego_pub_hash);
873   GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key),
874                       &place_pub_hash);
875
876   struct GNUNET_CRYPTO_HashAsciiEncoded ego_pub_hash_ascii;
877   struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
878   memcpy (&ego_pub_hash_ascii.encoding,
879           GNUNET_h2s_full (&ego_pub_hash), sizeof (ego_pub_hash_ascii));
880   memcpy (&place_pub_hash_ascii.encoding,
881           GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
882
883   char *filename = NULL;
884   GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
885                    dir_social, DIR_SEPARATOR,
886                    "places", DIR_SEPARATOR,
887                    ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
888                    place_pub_hash_ascii.encoding);
889   int ret = GNUNET_DISK_directory_create_for_file (filename);
890   if (GNUNET_OK != ret
891       || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size),
892                                    GNUNET_DISK_PERM_USER_READ
893                                    | GNUNET_DISK_PERM_USER_WRITE))
894   {
895     GNUNET_break (0);
896     ret = GNUNET_SYSERR;
897   }
898   GNUNET_free (filename);
899
900   if (ret == GNUNET_OK)
901   {
902     GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s",
903                      dir_social, DIR_SEPARATOR,
904                      "apps", DIR_SEPARATOR,
905                      app_id, DIR_SEPARATOR,
906                      ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
907                      place_pub_hash_ascii.encoding);
908     ret = GNUNET_DISK_directory_create_for_file (filename);
909     if (GNUNET_OK != ret
910         || 0 > GNUNET_DISK_fn_write (filename, "", 0,
911                                      GNUNET_DISK_PERM_USER_READ
912                                      | GNUNET_DISK_PERM_USER_WRITE))
913     {
914       GNUNET_break (0);
915       ret = GNUNET_SYSERR;
916     }
917     GNUNET_free (filename);
918   }
919   return ret;
920 }
921
922
923 int
924 app_place_remove (const char *app_id,
925                   const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key)
926 {
927   struct GNUNET_HashCode place_pub_hash;
928   GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash);
929
930   struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
931   memcpy (&place_pub_hash_ascii.encoding,
932           GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
933
934   char *app_place_filename = NULL;
935   GNUNET_asprintf (&app_place_filename,
936                    "%s%c" "%s%/",
937                    dir_social, DIR_SEPARATOR,
938                    "apps", DIR_SEPARATOR,
939                    app_id, DIR_SEPARATOR,
940                    place_pub_hash_ascii.encoding);
941
942   struct GNUNET_HashCode app_id_hash;
943   GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
944
945   struct GNUNET_CONTAINER_MultiHashMap *
946     app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
947
948   if (NULL != app_places)
949     GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL);
950
951   int ret = unlink (app_place_filename);
952   GNUNET_free (app_place_filename);
953   if (0 != ret)
954   {
955     GNUNET_break (0);
956     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
957                 "Error removing app place: unlink returned %d\n", errno);
958     return GNUNET_SYSERR;
959   }
960
961   return GNUNET_OK;
962 }
963
964
965 /**
966  * Enter place as host.
967  *
968  * @param req
969  *        Entry request.
970  * @param[out] ret_hst
971  *        Returned Host struct.
972  *
973  * @return #GNUNET_YES if the host entered the place just now,
974  *         #GNUNET_NO  if the place is already entered,
975  *         #GNUNET_SYSERR if place_pub_key was set
976  *                        but its private key was not found
977  */
978 static int
979 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
980 {
981   int ret = GNUNET_NO;
982   struct GNUNET_HashCode place_pub_hash;
983   GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key),
984                       &place_pub_hash);
985   struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
986
987   if (NULL == hst)
988   {
989     hst = GNUNET_new (struct Host);
990     hst->policy = hreq->policy;
991     hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
992
993     struct Place *plc = &hst->plc;
994     place_init (plc);
995     plc->is_host = GNUNET_YES;
996     plc->pub_key = hreq->place_pub_key;
997     plc->pub_key_hash = place_pub_hash;
998
999     GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
1000                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1001     hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy,
1002                                             &psyc_master_started,
1003                                             &psyc_recv_join_request,
1004                                             &psyc_recv_message, NULL, hst);
1005     hst->plc.channel = GNUNET_PSYC_master_get_channel (hst->master);
1006     ret = GNUNET_YES;
1007   }
1008
1009   if (NULL != ret_hst)
1010     *ret_hst = hst;
1011   return ret;
1012 }
1013
1014
1015 /**
1016  * Handle a connecting client entering a place as host.
1017  */
1018 static void
1019 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
1020                         const struct GNUNET_MessageHeader *msg)
1021 {
1022   struct HostEnterRequest *hreq
1023     = (struct HostEnterRequest *) GNUNET_copy_message (msg);
1024
1025   uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq);
1026   const char *app_id = NULL;
1027   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1],
1028                                                     app_id_size, 1, &app_id);
1029   if (0 == offset || offset != app_id_size || app_id == NULL)
1030   {
1031     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1032                 "offset = %u, app_id_size = %u, app_id = %s\n",
1033                 offset, app_id_size, app_id);
1034     GNUNET_break (0);
1035     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1036     return;
1037   }
1038
1039   struct Host *hst = NULL;
1040   struct Place *plc = NULL;
1041   int ret = GNUNET_OK;
1042
1043   struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key;
1044   memset (&empty_pub_key, 0, sizeof (empty_pub_key));
1045
1046   if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key)))
1047   { // no public key set: create new private key & save the place
1048     struct GNUNET_CRYPTO_EddsaPrivateKey *
1049       place_key = GNUNET_CRYPTO_eddsa_key_create ();
1050     hreq->place_key = *place_key;
1051     GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key);
1052     GNUNET_CRYPTO_eddsa_key_clear (place_key);
1053     GNUNET_free (place_key);
1054
1055     app_place_save (app_id, (const struct PlaceEnterRequest *) hreq);
1056   }
1057
1058   switch (host_enter (hreq, &hst))
1059   {
1060   case GNUNET_YES:
1061     plc = &hst->plc;
1062     break;
1063
1064   case GNUNET_NO:
1065   {
1066     plc = &hst->plc;
1067     client_send_host_enter_ack (client, hst, GNUNET_OK);
1068     break;
1069   }
1070   case GNUNET_SYSERR:
1071     ret = GNUNET_SYSERR;
1072   }
1073
1074   if (ret != GNUNET_SYSERR)
1075   {
1076
1077     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1078                 "%p Client connected as host to place %s.\n",
1079                 hst, GNUNET_h2s (&plc->pub_key_hash));
1080
1081     struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1082     cli->client = client;
1083     GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1084
1085     struct Client *ctx = GNUNET_new (struct Client);
1086     ctx->plc = plc;
1087     GNUNET_SERVER_client_set_user_context (client, ctx);
1088   }
1089
1090   GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key);
1091   GNUNET_free (hreq);
1092   GNUNET_SERVER_receive_done (client, ret);
1093 }
1094
1095
1096 /**
1097  * Enter place as guest.
1098  *
1099  * @param req
1100  *        Entry request.
1101  * @param[out] ret_gst
1102  *        Returned Guest struct.
1103  *
1104  * @return #GNUNET_YES if the guest entered the place just now,
1105  *         #GNUNET_NO  if the place is already entered,
1106  *         #GNUNET_SYSERR on error.
1107  */
1108 static int
1109 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
1110 {
1111   int ret = GNUNET_NO;
1112   uint16_t greq_size = ntohs (greq->header.size);
1113
1114   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key;
1115   struct GNUNET_HashCode ego_pub_hash;
1116   GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
1117   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
1118
1119   if (NULL == ego)
1120     return GNUNET_SYSERR;
1121
1122   struct GNUNET_HashCode place_pub_hash;
1123   GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key),
1124                       &place_pub_hash);
1125
1126   struct GNUNET_CONTAINER_MultiHashMap *
1127     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
1128   struct Guest *gst = NULL;
1129
1130   if (NULL != plc_gst)
1131     gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash);
1132
1133   if (NULL == gst || NULL == gst->slave)
1134   {
1135     gst = GNUNET_new (struct Guest);
1136     gst->origin = greq->origin;
1137     gst->relay_count = ntohl (greq->relay_count);
1138
1139     uint16_t len;
1140     uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1141     const char *app_id = (const char *) &greq[1];
1142     const char *p = app_id;
1143
1144     len = strnlen (app_id, remaining);
1145     if (len == remaining)
1146     {
1147       GNUNET_break (0);
1148       return GNUNET_SYSERR;
1149     }
1150     p += len + 1;
1151     remaining -= len + 1;
1152
1153     const struct GNUNET_PeerIdentity *relays = NULL;
1154     uint16_t relay_size = gst->relay_count * sizeof (*relays);
1155     if (remaining < relay_size)
1156     {
1157       GNUNET_break (0);
1158       return GNUNET_SYSERR;
1159     }
1160     if (0 < relay_size)
1161       relays = (const struct GNUNET_PeerIdentity *) p;
1162     p += relay_size;
1163     remaining -= relay_size;
1164
1165     struct GNUNET_PSYC_Message *join_msg = NULL;
1166     uint16_t join_msg_size = 0;
1167
1168     if (sizeof (struct GNUNET_MessageHeader) <= remaining)
1169     {
1170       join_msg = (struct GNUNET_PSYC_Message *) p;
1171       join_msg_size = ntohs (join_msg->header.size);
1172       p += join_msg_size;
1173       remaining -= join_msg_size;
1174     }
1175     if (0 != remaining)
1176     {
1177       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1178                   "%u + %u + %u != %u\n",
1179                   sizeof (*greq), relay_size, join_msg_size, greq_size);
1180       GNUNET_break (0);
1181       GNUNET_free (gst);
1182       return GNUNET_SYSERR;
1183     }
1184     if (0 < relay_size)
1185     {
1186       gst->relays = GNUNET_malloc (relay_size);
1187       memcpy (gst->relays, relays, relay_size);
1188     }
1189
1190     struct Place *plc = &gst->plc;
1191     place_init (plc);
1192     plc->is_host = GNUNET_NO;
1193     plc->pub_key = greq->place_pub_key;
1194     plc->pub_key_hash = place_pub_hash;
1195     plc->ego_pub_key = ego_pub_key;
1196     plc->ego_pub_hash = ego_pub_hash;
1197     plc->ego_key = ego->key;
1198
1199     if (NULL == plc_gst)
1200     {
1201       plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1202       (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
1203                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1204     }
1205     (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst,
1206                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1207     (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
1208                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1209     gst->slave
1210       = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key,
1211                                 &gst->origin, gst->relay_count, gst->relays,
1212                                 &psyc_recv_message, NULL, &psyc_slave_connected,
1213                                 &psyc_recv_join_dcsn, gst, join_msg);
1214     gst->plc.channel = GNUNET_PSYC_slave_get_channel (gst->slave);
1215     ret = GNUNET_YES;
1216   }
1217
1218   if (NULL != ret_gst)
1219     *ret_gst = gst;
1220   return ret;
1221 }
1222
1223
1224 /**
1225  * Handle a connecting client entering a place as guest.
1226  */
1227 static void
1228 client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
1229                          const struct GNUNET_MessageHeader *msg)
1230 {
1231   const struct GuestEnterRequest *
1232     greq = (const struct GuestEnterRequest *) msg;
1233
1234   uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1235   const char *app_id = NULL;
1236   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1],
1237                                                     remaining, 1, &app_id);
1238   if (0 == offset)
1239   {
1240     GNUNET_break (0);
1241     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1242     return;
1243   }
1244
1245   struct Guest *gst = NULL;
1246   struct Place *plc = NULL;
1247
1248   switch (guest_enter (greq, &gst))
1249   {
1250   case GNUNET_YES:
1251     plc = &gst->plc;
1252     app_place_save (app_id, (const struct PlaceEnterRequest *) greq);
1253     break;
1254
1255   case GNUNET_NO:
1256   {
1257     plc = &gst->plc;
1258
1259     struct GNUNET_PSYC_CountersResultMessage res;
1260     res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
1261     res.header.size = htons (sizeof (res));
1262     res.result_code = htonl (GNUNET_OK);
1263     res.max_message_id = GNUNET_htonll (plc->max_message_id);
1264
1265     client_send_msg (client, &res.header);
1266     if (NULL != gst->join_dcsn)
1267       client_send_msg (client, &gst->join_dcsn->header);
1268
1269     break;
1270   }
1271   case GNUNET_SYSERR:
1272     GNUNET_break (0);
1273     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1274     return;
1275   }
1276
1277   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1278               "%p Client connected as guest to place %s.\n",
1279               gst, GNUNET_h2s (&plc->pub_key_hash));
1280
1281   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1282   cli->client = client;
1283   GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1284
1285   struct Client *ctx = GNUNET_new (struct Client);
1286   ctx->plc = plc;
1287   GNUNET_SERVER_client_set_user_context (client, ctx);
1288   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1289 }
1290
1291
1292 struct GuestEnterByNameClosure
1293 {
1294   struct GNUNET_SERVER_Client *client;
1295   char *app_id;
1296   char *password;
1297   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1298   struct GNUNET_MessageHeader *join_msg;
1299 };
1300
1301
1302 /**
1303  * Result of a GNS name lookup for entering a place.
1304  *
1305  * @see GNUNET_SOCIAL_guest_enter_by_name
1306  */
1307 static void
1308 gns_result_guest_enter (void *cls, uint32_t rd_count,
1309                         const struct GNUNET_GNSRECORD_Data *rd)
1310 {
1311   struct GuestEnterByNameClosure *gcls = cls;
1312   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1313               "%p GNS result: %u records.\n", gcls->client, rd_count);
1314
1315   const struct GNUNET_GNSRECORD_PlaceData *
1316     rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1317
1318   if (0 == rd_count || rd->data_size < sizeof (*rec))
1319   {
1320     GNUNET_break (0);
1321     GNUNET_SERVER_receive_done (gcls->client, GNUNET_SYSERR);
1322     return;
1323   }
1324
1325   uint16_t relay_count = ntohl (rec->relay_count);
1326   struct GNUNET_PeerIdentity *relays = NULL;
1327
1328   if (0 < relay_count)
1329   {
1330     if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity))
1331     {
1332       relays = (struct GNUNET_PeerIdentity *) &rec[1];
1333     }
1334     else
1335     {
1336       relay_count = 0;
1337       GNUNET_break_op (0);
1338     }
1339   }
1340
1341   uint16_t app_id_size = strlen (gcls->app_id) + 1;
1342   uint16_t relay_size = relay_count * sizeof (*relays);
1343   uint16_t join_msg_size = 0;
1344   if (NULL != gcls->join_msg)
1345     join_msg_size = ntohs (gcls->join_msg->size);
1346   uint16_t greq_size = sizeof (struct GuestEnterRequest)
1347     + app_id_size + relay_size + join_msg_size;
1348   struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
1349   greq->header.size = htons (greq_size);
1350   greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1351   greq->ego_pub_key = gcls->ego_pub_key;
1352   greq->place_pub_key = rec->place_pub_key;
1353   greq->origin = rec->origin;
1354   greq->relay_count = rec->relay_count;
1355
1356   void *p = &greq[1];
1357   memcpy (p, gcls->app_id, app_id_size);
1358   p += app_id_size;
1359   memcpy (p, relays, relay_size);
1360   p += relay_size;
1361   memcpy (p, gcls->join_msg, join_msg_size);
1362
1363   client_recv_guest_enter (NULL, gcls->client, &greq->header);
1364
1365   GNUNET_free (gcls->app_id);
1366   if (NULL != gcls->password)
1367     GNUNET_free (gcls->password);
1368   if (NULL != gcls->join_msg)
1369     GNUNET_free (gcls->join_msg);
1370   GNUNET_free (gcls);
1371   GNUNET_free (greq);
1372 }
1373
1374
1375 /**
1376  * Handle a connecting client entering a place as guest using a GNS address.
1377  *
1378  * Look up GNS address and generate a GuestEnterRequest from that.
1379  */
1380 static void
1381 client_recv_guest_enter_by_name (void *cls, struct GNUNET_SERVER_Client *client,
1382                                  const struct GNUNET_MessageHeader *msg)
1383 {
1384   const struct GuestEnterByNameRequest *
1385     greq = (const struct GuestEnterByNameRequest *) msg;
1386
1387   struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls));
1388   gcls->client = client;
1389   gcls->ego_pub_key = greq->ego_pub_key;
1390
1391   const char *p = (const char *) &greq[1];
1392   const char *app_id = NULL, *password = NULL, *gns_name = NULL;
1393   uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1394   uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3,
1395                                                     &app_id,
1396                                                     &gns_name,
1397                                                     &password);
1398   p += offset;
1399   remaining -= offset;
1400
1401   if (0 != offset && sizeof (*gcls->join_msg) <= remaining)
1402   {
1403     gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p);
1404     remaining -= ntohs (gcls->join_msg->size);
1405   }
1406
1407   if (0 == offset || 0 != remaining)
1408   {
1409     if (NULL != gcls->join_msg)
1410       GNUNET_free (gcls->join_msg);
1411     GNUNET_break (0);
1412     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1413     return;
1414   }
1415
1416   uint16_t app_id_size = strlen (app_id) + 1;
1417   gcls->app_id = GNUNET_malloc (app_id_size);
1418   memcpy (gcls->app_id, app_id, app_id_size);
1419
1420   uint16_t password_size = strlen (password);
1421   if (0 < password_size++)
1422   {
1423     gcls->password = GNUNET_malloc (password_size);
1424     memcpy (gcls->password, password, password_size);
1425   }
1426
1427   GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key,
1428                      GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1429                      NULL, gns_result_guest_enter, gcls);
1430 }
1431
1432
1433 void
1434 app_notify_place (struct GNUNET_MessageHeader *msg,
1435                   struct GNUNET_SERVER_Client *client)
1436 {
1437   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1438               "%p Sending place notification of type %u to client.\n",
1439               client, ntohs (msg->type));
1440
1441   uint16_t msg_size = ntohs (msg->size);
1442   struct AppPlaceMessage amsg;
1443   amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1444   amsg.header.size = htons (sizeof (amsg));
1445
1446   switch (ntohs (msg->type))
1447   {
1448   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1449     if (msg_size < sizeof (struct HostEnterRequest))
1450       return;
1451     struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1452     amsg.is_host = GNUNET_YES;
1453     amsg.ego_pub_key = hreq->ego_pub_key;
1454     amsg.place_pub_key = hreq->place_pub_key;
1455     break;
1456
1457   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1458     if (msg_size < sizeof (struct GuestEnterRequest))
1459       return;
1460     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1461     amsg.is_host = GNUNET_NO;
1462     amsg.ego_pub_key = greq->ego_pub_key;
1463     amsg.place_pub_key = greq->place_pub_key;
1464     break;
1465
1466   default:
1467     return;
1468   }
1469
1470   client_send_msg (client, &amsg.header);
1471 }
1472
1473
1474 void
1475 app_notify_ego (struct Ego *ego, struct GNUNET_SERVER_Client *client)
1476 {
1477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1478               "%p Sending ego notification to client: %s\n",
1479               client, ego->name);
1480
1481   size_t name_size = strlen (ego->name) + 1;
1482   struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size);
1483   emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
1484   emsg->header.size = htons (sizeof (*emsg) + name_size);
1485
1486   GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
1487   memcpy (&emsg[1], ego->name, name_size);
1488
1489   client_send_msg (client, &emsg->header);
1490   GNUNET_free (emsg);
1491 }
1492
1493
1494 int
1495 app_place_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
1496 {
1497   struct GNUNET_MessageHeader *
1498     msg = GNUNET_CONTAINER_multihashmap_get (places, key);
1499   if (NULL != msg)
1500     app_notify_place (msg, cls);
1501   return GNUNET_YES;
1502 }
1503
1504
1505 int
1506 ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
1507 {
1508   app_notify_ego (value, cls);
1509   return GNUNET_YES;
1510 }
1511
1512
1513 /**
1514  * Handle application connection.
1515  */
1516 static void
1517 client_recv_app_connect (void *cls, struct GNUNET_SERVER_Client *client,
1518                          const struct GNUNET_MessageHeader *msg)
1519 {
1520   const struct AppConnectRequest *creq
1521     = (const struct AppConnectRequest *) msg;
1522
1523   uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
1524   const char *app_id = NULL;
1525   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
1526                                                     app_id_size, 1, &app_id);
1527   if (0 == offset || offset != app_id_size)
1528   {
1529     GNUNET_break (0);
1530     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1531     return;
1532   }
1533
1534   struct GNUNET_HashCode app_id_hash;
1535   GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash);
1536
1537   GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
1538
1539   struct GNUNET_CONTAINER_MultiHashMap *
1540     app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1541   if (NULL != app_places)
1542     GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry, client);
1543
1544   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1545   cli->client = client;
1546   struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
1547                                                                &app_id_hash);
1548   if (NULL == app) {
1549     app = GNUNET_malloc (sizeof (*app));
1550     (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
1551                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1552   }
1553   GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
1554
1555   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1556               "%p Application %s connected.\n", app, app_id);
1557
1558   struct Client *ctx = GNUNET_new (struct Client);
1559   ctx->app_id = GNUNET_malloc (app_id_size);
1560   memcpy (ctx->app_id, app_id, app_id_size);
1561
1562   GNUNET_SERVER_client_set_user_context (client, ctx);
1563   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1564 }
1565
1566
1567 /**
1568  * Handle application detach request.
1569  */
1570 static void
1571 client_recv_app_detach (void *cls, struct GNUNET_SERVER_Client *client,
1572                          const struct GNUNET_MessageHeader *msg)
1573 {
1574   struct Client *
1575     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1576   GNUNET_assert (NULL != ctx);
1577
1578   const struct AppDetachRequest *req
1579     = (const struct AppDetachRequest *) msg;
1580
1581   int ret = app_place_remove (ctx->app_id, &req->place_pub_key);
1582   client_send_result (client, req->op_id, ret, NULL, 0);
1583
1584   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1585 }
1586
1587
1588 /**
1589  * Handle application detach request.
1590  */
1591 static void
1592 client_recv_place_leave (void *cls, struct GNUNET_SERVER_Client *client,
1593                          const struct GNUNET_MessageHeader *msg)
1594 {
1595   struct Client *
1596     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1597   GNUNET_assert (NULL != ctx);
1598   struct Place *plc = ctx->plc;
1599
1600   /* Disconnect all clients connected to the place */
1601   /* FIXME: disconnect from the network, but keep local connection for history access */
1602   struct ClientListItem *cli = plc->clients_head, *next;
1603   while (NULL != cli)
1604   {
1605     GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
1606     GNUNET_SERVER_client_disconnect (cli->client);
1607     next = cli->next;
1608     GNUNET_free (cli);
1609     cli = next;
1610   }
1611
1612   if (GNUNET_YES != plc->is_disconnected)
1613   {
1614     plc->is_disconnected = GNUNET_YES;
1615     if (NULL != plc->tmit_msgs_head)
1616     { /* Send pending messages to PSYC before cleanup. */
1617       psyc_transmit_message (plc);
1618     }
1619     else
1620     {
1621       cleanup_place (plc);
1622     }
1623   }
1624 }
1625
1626
1627 struct JoinDecisionClosure
1628 {
1629   int32_t is_admitted;
1630   struct GNUNET_PSYC_Message *msg;
1631 };
1632
1633
1634 /**
1635  * Iterator callback for responding to join requests.
1636  */
1637 static int
1638 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1639                          void *value)
1640 {
1641   struct JoinDecisionClosure *jcls = cls;
1642   struct GNUNET_PSYC_JoinHandle *jh = value;
1643   // FIXME: add relays
1644   GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1645   return GNUNET_YES;
1646 }
1647
1648
1649 /**
1650  * Handle an entry decision from a host client.
1651  */
1652 static void
1653 client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
1654                            const struct GNUNET_MessageHeader *msg)
1655 {
1656   struct Client *
1657     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1658   GNUNET_assert (NULL != ctx);
1659   struct Place *plc = ctx->plc;
1660   GNUNET_assert (GNUNET_YES == plc->is_host);
1661   struct Host *hst = (struct Host *) plc;
1662
1663   struct GNUNET_PSYC_JoinDecisionMessage *
1664     dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
1665   struct JoinDecisionClosure jcls;
1666   jcls.is_admitted = ntohl (dcsn->is_admitted);
1667   jcls.msg
1668     = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
1669     ? (struct GNUNET_PSYC_Message *) &dcsn[1]
1670     : NULL;
1671
1672   struct GNUNET_HashCode slave_key_hash;
1673   GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
1674                       &slave_key_hash);
1675
1676   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1677               "%p Got join decision (%d) from client for place %s..\n",
1678               hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
1679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1680               "%p ..and slave %s.\n",
1681               hst, GNUNET_h2s (&slave_key_hash));
1682
1683   GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
1684                                               &psyc_send_join_decision, &jcls);
1685   GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
1686   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1687 }
1688
1689
1690 /**
1691  * Send acknowledgement to a client.
1692  *
1693  * Sent after a message fragment has been passed on to multicast.
1694  *
1695  * @param plc The place struct for the client.
1696  */
1697 static void
1698 send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
1699 {
1700   struct GNUNET_MessageHeader res;
1701   res.size = htons (sizeof (res));
1702   res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
1703   client_send_msg (client, &res);
1704 }
1705
1706
1707 /**
1708  * Proceed to the next message part in the transmission queue.
1709  *
1710  * @param plc
1711  *        Place where the transmission is going on.
1712  * @param tmit_msg
1713  *        Currently transmitted message.
1714  * @param tmit_frag
1715  *        Currently transmitted message fragment.
1716  *
1717  * @return @a tmit_frag, or NULL if reached the end of fragment.
1718  */
1719 static struct FragmentTransmitQueue *
1720 psyc_transmit_queue_next_part (struct Place *plc,
1721                                struct MessageTransmitQueue *tmit_msg,
1722                                struct FragmentTransmitQueue *tmit_frag)
1723 {
1724   uint16_t psize = ntohs (tmit_frag->next_part->size);
1725   if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
1726       < tmit_frag->size)
1727   {
1728     tmit_frag->next_part
1729       = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
1730   }
1731   else /* Reached end of current fragment. */
1732   {
1733     if (NULL != tmit_frag->client)
1734       send_message_ack (plc, tmit_frag->client);
1735     GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1736     GNUNET_free (tmit_frag);
1737     tmit_frag = NULL;
1738   }
1739   return tmit_frag;
1740 }
1741
1742
1743 /**
1744  * Proceed to next message in transmission queue.
1745  *
1746  * @param plc
1747  *        Place where the transmission is going on.
1748  * @param tmit_msg
1749  *        Currently transmitted message.
1750  *
1751  * @return The next message in queue, or NULL if queue is empty.
1752  */
1753 static struct MessageTransmitQueue *
1754 psyc_transmit_queue_next_msg (struct Place *plc,
1755                               struct MessageTransmitQueue *tmit_msg)
1756 {
1757   GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1758   GNUNET_free (tmit_msg);
1759   return plc->tmit_msgs_head;
1760 }
1761
1762
1763 /**
1764  * Callback for data transmission to PSYC.
1765  */
1766 static int
1767 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1768 {
1769   struct Place *plc = cls;
1770   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1771   GNUNET_assert (NULL != tmit_msg);
1772   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1773   if (NULL == tmit_frag)
1774   { /* Rest of the message have not arrived yet, pause transmission */
1775     *data_size = 0;
1776     return GNUNET_NO;
1777   }
1778   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1779   if (NULL == pmsg)
1780   {
1781     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1782                 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
1783     *data_size = 0;
1784     return GNUNET_NO;
1785   }
1786
1787   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1788               "%p psyc_transmit_notify_data()\n", plc);
1789   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1790
1791   uint16_t ptype = ntohs (pmsg->type);
1792   uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
1793   int ret;
1794
1795   switch (ptype)
1796   {
1797   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1798     if (*data_size < pdata_size)
1799     {
1800       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1801                 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
1802       *data_size = 0;
1803       return GNUNET_NO;
1804     }
1805     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1806                 "%p psyc_transmit_notify_data: sending %u bytes.\n",
1807                 plc, pdata_size);
1808
1809     *data_size = pdata_size;
1810     memcpy (data, &pmsg[1], *data_size);
1811     ret = GNUNET_NO;
1812     break;
1813
1814   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1815     *data_size = 0;
1816     ret = GNUNET_YES;
1817     break;
1818
1819   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1820     *data_size = 0;
1821     ret = GNUNET_SYSERR;
1822     break;
1823
1824   default:
1825     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1826                 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
1827                 plc, ptype);
1828     ret = GNUNET_SYSERR;
1829   }
1830
1831   if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
1832   {
1833     *data_size = 0;
1834     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1835     plc->is_disconnected = GNUNET_YES;
1836     GNUNET_SERVER_client_disconnect (tmit_frag->client);
1837     GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1838     return ret;
1839   }
1840   else
1841   {
1842     tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1843     if (NULL != tmit_frag)
1844     {
1845       struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1846       ptype = ntohs (pmsg->type);
1847       switch (ptype)
1848       {
1849       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1850         ret = GNUNET_YES;
1851         break;
1852       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1853         ret = GNUNET_SYSERR;
1854         break;
1855       }
1856       switch (ptype)
1857       {
1858       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1859       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1860         tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1861       }
1862     }
1863
1864     if (NULL == tmit_msg->frags_head
1865         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1866     { /* Reached end of current message. */
1867       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1868     }
1869   }
1870
1871   if (ret != GNUNET_NO)
1872   {
1873     if (NULL != tmit_msg)
1874     {
1875       psyc_transmit_message (plc);
1876     }
1877     else if (GNUNET_YES == plc->is_disconnected)
1878     {
1879       /* FIXME: handle partial message (when still in_transmit) */
1880       cleanup_place (plc);
1881     }
1882   }
1883   return ret;
1884 }
1885
1886
1887 /**
1888  * Callback for modifier transmission to PSYC.
1889  */
1890 static int
1891 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1892                           uint8_t *oper, uint32_t *full_value_size)
1893 {
1894   struct Place *plc = cls;
1895   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1896   GNUNET_assert (NULL != tmit_msg);
1897   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1898   if (NULL == tmit_frag)
1899   { /* Rest of the message have not arrived yet, pause transmission */
1900     *data_size = 0;
1901     return GNUNET_NO;
1902   }
1903   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1904   if (NULL == pmsg)
1905   {
1906     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1907                 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
1908     *data_size = 0;
1909     return GNUNET_NO;
1910   }
1911
1912   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1913               "%p psyc_transmit_notify_mod()\n", plc);
1914   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1915
1916   uint16_t ptype = ntohs (pmsg->type);
1917   int ret;
1918
1919   switch (ptype)
1920   {
1921   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1922   {
1923     if (NULL == oper)
1924     {
1925       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1926                   "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
1927       ret = GNUNET_SYSERR;
1928       break;
1929     }
1930     struct GNUNET_PSYC_MessageModifier *
1931       pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
1932     uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
1933
1934     if (*data_size < mod_size)
1935     {
1936       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1937                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1938       *data_size = 0;
1939       return GNUNET_NO;
1940     }
1941
1942     *full_value_size = ntohl (pmod->value_size);
1943     *oper = pmod->oper;
1944     *data_size = mod_size;
1945     memcpy (data, &pmod[1], mod_size);
1946     ret = GNUNET_NO;
1947     break;
1948   }
1949
1950   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1951   {
1952     if (NULL != oper)
1953     {
1954       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1955                   "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
1956       ret = GNUNET_SYSERR;
1957       break;
1958     }
1959     uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
1960     if (*data_size < mod_size)
1961     {
1962       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1963                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1964       *data_size = 0;
1965       return GNUNET_NO;
1966     }
1967     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1968                 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
1969
1970     *data_size = mod_size;
1971     memcpy (data, &pmsg[1], *data_size);
1972     ret = GNUNET_NO;
1973     break;
1974   }
1975
1976   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1977   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1978   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1979     *data_size = 0;
1980     ret = GNUNET_YES;
1981     break;
1982
1983   default:
1984     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1985                 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
1986                 plc, ptype);
1987     ret = GNUNET_SYSERR;
1988   }
1989
1990   if (GNUNET_SYSERR == ret)
1991   {
1992     *data_size = 0;
1993     ret = GNUNET_SYSERR;
1994     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1995     plc->is_disconnected = GNUNET_YES;
1996     GNUNET_SERVER_client_disconnect (tmit_frag->client);
1997     GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1998   }
1999   else
2000   {
2001     if (GNUNET_YES != ret)
2002       psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2003
2004     if (NULL == tmit_msg->frags_head
2005         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2006     { /* Reached end of current message. */
2007       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2008     }
2009   }
2010   return ret;
2011 }
2012
2013 /**
2014  * Callback for data transmission from a host to PSYC.
2015  */
2016 static int
2017 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2018 {
2019   int ret = psyc_transmit_notify_data (cls, data_size, data);
2020
2021   if (GNUNET_NO != ret)
2022   {
2023     struct Host *hst = cls;
2024     hst->tmit_handle = NULL;
2025   }
2026   return ret;
2027 }
2028
2029
2030 /**
2031  * Callback for the transmit functions of multicast.
2032  */
2033 static int
2034 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2035 {
2036   int ret = psyc_transmit_notify_data (cls, data_size, data);
2037
2038   if (GNUNET_NO != ret)
2039   {
2040     struct Guest *gst = cls;
2041     gst->tmit_handle = NULL;
2042   }
2043   return ret;
2044 }
2045
2046
2047 /**
2048  * Callback for modifier transmission from a host to PSYC.
2049  */
2050 static int
2051 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2052                           uint8_t *oper, uint32_t *full_value_size)
2053 {
2054   int ret = psyc_transmit_notify_mod (cls, data_size, data,
2055                                       oper, full_value_size);
2056   if (GNUNET_SYSERR == ret)
2057   {
2058     struct Host *hst = cls;
2059     hst->tmit_handle = NULL;
2060   }
2061   return ret;
2062 }
2063
2064
2065 /**
2066  * Callback for modifier transmission from a guest to PSYC.
2067  */
2068 static int
2069 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2070                            uint8_t *oper, uint32_t *full_value_size)
2071 {
2072   int ret = psyc_transmit_notify_mod (cls, data_size, data,
2073                                       oper, full_value_size);
2074   if (GNUNET_SYSERR == ret)
2075   {
2076     struct Guest *gst = cls;
2077     gst->tmit_handle = NULL;
2078   }
2079   return ret;
2080 }
2081
2082
2083 /**
2084  * Get method part of next message from transmission queue.
2085  *
2086  * @param tmit_msg
2087  *        Next item in message transmission queue.
2088  * @param[out] pmeth
2089  *        The message method is returned here.
2090  *
2091  * @return #GNUNET_OK on success
2092  *         #GNUNET_NO if there are no more messages in queue.
2093  *         #GNUNET_SYSERR if the next message is malformed.
2094  */
2095 static int
2096 psyc_transmit_queue_next_method (struct Place *plc,
2097                                  struct GNUNET_PSYC_MessageMethod **pmeth)
2098 {
2099   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2100   if (NULL == tmit_msg)
2101     return GNUNET_NO;
2102
2103   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2104   if (NULL == tmit_frag)
2105   {
2106     GNUNET_break (0);
2107     return GNUNET_NO;
2108   }
2109
2110   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2111   if (NULL == pmsg
2112       || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
2113   {
2114     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2115                 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
2116                 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
2117     GNUNET_break (0);
2118     return GNUNET_SYSERR;
2119   }
2120
2121   uint16_t psize = ntohs (pmsg->size);
2122   *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
2123   if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
2124   {
2125     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2126                 "%p psyc_transmit_queue_next_method: invalid method name.\n",
2127                 plc, ntohs (pmsg->type));
2128     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2129                 "%u <= %u || NUL != %u\n",
2130                 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
2131     GNUNET_break (0);
2132     return GNUNET_SYSERR;
2133   }
2134
2135   psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2136   return GNUNET_OK;
2137 }
2138
2139
2140 /**
2141  * Transmit the next message in queue from the host to the PSYC channel.
2142  */
2143 static int
2144 psyc_master_transmit_message (struct Host *hst)
2145 {
2146
2147   if (NULL == hst->tmit_handle)
2148   {
2149     struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2150     int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
2151     if (GNUNET_OK != ret)
2152       return ret;
2153
2154     hst->tmit_handle
2155       = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
2156                                      &host_transmit_notify_mod,
2157                                      &host_transmit_notify_data, hst,
2158                                      pmeth->flags);
2159   }
2160   else
2161   {
2162     GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
2163   }
2164   return GNUNET_OK;
2165 }
2166
2167
2168 /**
2169  * Transmit the next message in queue from a guest to the PSYC channel.
2170  */
2171 static int
2172 psyc_slave_transmit_message (struct Guest *gst)
2173 {
2174   if (NULL == gst->tmit_handle)
2175   {
2176     struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
2177     int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
2178     if (GNUNET_OK != ret)
2179       return ret;
2180
2181     gst->tmit_handle
2182       = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
2183                                     &guest_transmit_notify_mod,
2184                                     &guest_transmit_notify_data, gst,
2185                                     pmeth->flags);
2186   }
2187   else
2188   {
2189     GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
2190   }
2191   return GNUNET_OK;
2192 }
2193
2194
2195 /**
2196  * Transmit a message to PSYC.
2197  */
2198 static int
2199 psyc_transmit_message (struct Place *plc)
2200 {
2201   return
2202     (plc->is_host)
2203     ? psyc_master_transmit_message ((struct Host *) plc)
2204     : psyc_slave_transmit_message ((struct Guest *) plc);
2205 }
2206
2207
2208 /**
2209  * Queue message parts for sending to PSYC.
2210  *
2211  * @param plc          Place to send to.
2212  * @param client       Client the message originates from.
2213  * @param data_size    Size of @a data.
2214  * @param data         Concatenated message parts.
2215  * @param first_ptype  First message part type in @a data.
2216  * @param last_ptype   Last message part type in @a data.
2217  */
2218 static struct MessageTransmitQueue *
2219 psyc_transmit_queue_message (struct Place *plc,
2220                              struct GNUNET_SERVER_Client *client,
2221                              size_t data_size,
2222                              const void *data,
2223                              uint16_t first_ptype, uint16_t last_ptype,
2224                              struct MessageTransmitQueue *tmit_msg)
2225 {
2226   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
2227   {
2228     tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
2229     GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2230   }
2231   else if (NULL == tmit_msg)
2232   {
2233     return NULL;
2234   }
2235
2236   struct FragmentTransmitQueue *
2237     tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
2238   memcpy (&tmit_frag[1], data, data_size);
2239   tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
2240   tmit_frag->client = client;
2241   tmit_frag->size = data_size;
2242
2243   GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2244   tmit_msg->client = client;
2245   return tmit_msg;
2246 }
2247
2248
2249 /**
2250  * Cancel transmission of current message to PSYC.
2251  *
2252  * @param plc     Place to send to.
2253  * @param client  Client the message originates from.
2254  */
2255 static void
2256 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
2257 {
2258   uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2259
2260   struct GNUNET_MessageHeader msg;
2261   msg.size = htons (sizeof (msg));
2262   msg.type = htons (type);
2263
2264   psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
2265   psyc_transmit_message (plc);
2266
2267   /* FIXME: cleanup */
2268 }
2269
2270
2271 /**
2272  * Handle an incoming message from a client, to be transmitted to the place.
2273  */
2274 static void
2275 client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
2276                           const struct GNUNET_MessageHeader *msg)
2277 {
2278   struct Client *
2279     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2280   GNUNET_assert (NULL != ctx);
2281   struct Place *plc = ctx->plc;
2282   int ret = GNUNET_SYSERR;
2283
2284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2285               "%p Received message from client.\n", plc);
2286   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2287
2288   if (GNUNET_YES != plc->is_ready)
2289   {
2290     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2291                 "%p Place is not ready yet, disconnecting client.\n", plc);
2292     GNUNET_break (0);
2293     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2294     return;
2295   }
2296
2297   uint16_t size = ntohs (msg->size);
2298   uint16_t psize = size - sizeof (*msg);
2299   if (psize < sizeof (struct GNUNET_MessageHeader)
2300       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
2301   {
2302     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2303                 "%p Received message with invalid payload size (%u) from client.\n",
2304                 plc, psize);
2305     GNUNET_break (0);
2306     psyc_transmit_cancel (plc, client);
2307     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2308     return;
2309   }
2310
2311   uint16_t first_ptype = 0, last_ptype = 0;
2312   if (GNUNET_SYSERR
2313       == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
2314                                           &first_ptype, &last_ptype))
2315   {
2316     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2317                 "%p Received invalid message part from client.\n", plc);
2318     GNUNET_break (0);
2319     psyc_transmit_cancel (plc, client);
2320     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2321     return;
2322   }
2323   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324               "%p Received message with first part type %u and last part type %u.\n",
2325               plc, first_ptype, last_ptype);
2326
2327   ctx->tmit_msg
2328     = psyc_transmit_queue_message (plc, client, psize, &msg[1],
2329                                    first_ptype, last_ptype, ctx->tmit_msg);
2330   if (NULL != ctx->tmit_msg)
2331   {
2332     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
2333       ctx->tmit_msg = NULL;
2334     ret = psyc_transmit_message (plc);
2335   }
2336
2337   if (GNUNET_OK != ret)
2338   {
2339     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2340                 "%p Received invalid message part from client.\n", plc);
2341     GNUNET_break (0);
2342     psyc_transmit_cancel (plc, client);
2343     ret = GNUNET_SYSERR;
2344   }
2345   GNUNET_SERVER_receive_done (client, ret);
2346 }
2347
2348
2349 /**
2350  * A historic message arrived from PSYC.
2351  */
2352 static void
2353 psyc_recv_history_message (void *cls, uint64_t message_id, uint32_t flags,
2354                            const struct GNUNET_PSYC_MessageHeader *msg)
2355 {
2356   struct OperationClosure *opcls = cls;
2357   struct Place *plc = opcls->plc;
2358
2359   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2360               "%p Received historic message #%" PRId64 " (flags: %x)\n",
2361               plc, message_id, flags);
2362
2363   uint16_t size = ntohs (msg->header.size);
2364
2365   struct GNUNET_OperationResultMessage *
2366     res = GNUNET_malloc (sizeof (*res) + size);
2367   res->header.size = htons (sizeof (*res) + size);
2368   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
2369   res->op_id = opcls->op_id;
2370   res->result_code = GNUNET_htonll (GNUNET_OK);
2371
2372   memcpy (&res[1], msg, size);
2373
2374   /** @todo FIXME: send only to requesting client */
2375   place_send_msg (plc, &res->header);
2376 }
2377
2378
2379 /**
2380  * Result of message history replay from PSYC.
2381  */
2382 static void
2383 psyc_recv_history_result (void *cls, int64_t result,
2384                           const void *err_msg, uint16_t err_msg_size)
2385 {
2386   struct OperationClosure *opcls = cls;
2387   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388               "%p History replay #%" PRIu64 ": "
2389               "PSYCstore returned %" PRId64 " (%.*s)\n",
2390               opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2391
2392   // FIXME: place might have been destroyed
2393   client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2394 }
2395
2396
2397 /**
2398  * Client requests channel history.
2399  */
2400 static void
2401 client_recv_history_replay (void *cls, struct GNUNET_SERVER_Client *client,
2402                             const struct GNUNET_MessageHeader *msg)
2403 {
2404   struct Client *
2405     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2406   GNUNET_assert (NULL != ctx);
2407   struct Place *plc = ctx->plc;
2408
2409   const struct GNUNET_PSYC_HistoryRequestMessage *
2410     req = (const struct GNUNET_PSYC_HistoryRequestMessage *) msg;
2411   uint16_t size = ntohs (msg->size);
2412   const char *method_prefix = (const char *) &req[1];
2413
2414   if (size < sizeof (*req) + 1
2415       || '\0' != method_prefix[size - sizeof (*req) - 1])
2416   {
2417     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2418                 "%p History replay #%" PRIu64 ": "
2419                 "invalid method prefix. size: %u < %u?\n",
2420                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2421     GNUNET_break (0);
2422     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2423     return;
2424   }
2425
2426   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2427   opcls->client = client;
2428   opcls->plc = plc;
2429   opcls->op_id = req->op_id;
2430   opcls->flags = ntohl (req->flags);
2431
2432   if (0 == req->message_limit)
2433     GNUNET_PSYC_channel_history_replay (plc->channel,
2434                                         GNUNET_ntohll (req->start_message_id),
2435                                         GNUNET_ntohll (req->end_message_id),
2436                                         method_prefix, opcls->flags,
2437                                         &psyc_recv_history_message, NULL,
2438                                         &psyc_recv_history_result, opcls);
2439   else
2440     GNUNET_PSYC_channel_history_replay_latest (plc->channel,
2441                                                GNUNET_ntohll (req->message_limit),
2442                                                method_prefix, opcls->flags,
2443                                                &psyc_recv_history_message, NULL,
2444                                                &psyc_recv_history_result, opcls);
2445
2446   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2447 }
2448
2449
2450 /**
2451  * A state variable part arrived from PSYC.
2452  */
2453 void
2454 psyc_recv_state_var (void *cls,
2455                      const struct GNUNET_MessageHeader *mod,
2456                      const char *name,
2457                      const void *value,
2458                      uint32_t value_size,
2459                      uint32_t full_value_size)
2460 {
2461   struct OperationClosure *opcls = cls;
2462   struct Place *plc = opcls->plc;
2463
2464   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465               "%p Received state variable %s from PSYC\n",
2466               plc, name);
2467
2468   uint16_t size = ntohs (mod->size);
2469
2470   struct GNUNET_OperationResultMessage *
2471     res = GNUNET_malloc (sizeof (*res) + size);
2472   res->header.size = htons (sizeof (*res) + size);
2473   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
2474   res->op_id = opcls->op_id;
2475   res->result_code = GNUNET_htonll (GNUNET_OK);
2476
2477   memcpy (&res[1], mod, size);
2478
2479   /** @todo FIXME: send only to requesting client */
2480   place_send_msg (plc, &res->header);
2481 }
2482
2483
2484 /**
2485  * Result of retrieving state variable from PSYC.
2486  */
2487 static void
2488 psyc_recv_state_result (void *cls, int64_t result,
2489                         const void *err_msg, uint16_t err_msg_size)
2490 {
2491   struct OperationClosure *opcls = cls;
2492   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2493               "%p State get #%" PRIu64 ": "
2494               "PSYCstore returned %" PRId64 " (%.*s)\n",
2495               opcls->plc, GNUNET_ntohll (opcls->op_id), result, err_msg_size, err_msg);
2496
2497   // FIXME: place might have been destroyed
2498   client_send_result (opcls->client, opcls->op_id, result, err_msg, err_msg_size);
2499 }
2500
2501
2502 /**
2503  * Client requests channel history.
2504  */
2505 static void
2506 client_recv_state_get (void *cls, struct GNUNET_SERVER_Client *client,
2507                        const struct GNUNET_MessageHeader *msg)
2508 {
2509   struct Client *
2510     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
2511   GNUNET_assert (NULL != ctx);
2512   struct Place *plc = ctx->plc;
2513
2514   const struct GNUNET_PSYC_StateRequestMessage *
2515     req = (const struct GNUNET_PSYC_StateRequestMessage *) msg;
2516   uint16_t size = ntohs (msg->size);
2517   const char *name = (const char *) &req[1];
2518
2519   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2520               "%p State get #%" PRIu64 ": %s\n",
2521               plc, GNUNET_ntohll (req->op_id), name);
2522
2523   if (size < sizeof (*req) + 1
2524       || '\0' != name[size - sizeof (*req) - 1])
2525   {
2526     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2527                 "%p State get #%" PRIu64 ": "
2528                 "invalid name. size: %u < %u?\n",
2529                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
2530     GNUNET_break (0);
2531     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2532     return;
2533   }
2534
2535   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
2536   opcls->client = client;
2537   opcls->plc = plc;
2538   opcls->op_id = req->op_id;
2539
2540   switch (ntohs (msg->type))
2541   {
2542   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
2543       GNUNET_PSYC_channel_state_get (plc->channel, name,
2544                                      psyc_recv_state_var,
2545                                      psyc_recv_state_result, opcls);
2546       break;
2547
2548   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
2549       GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
2550                                             psyc_recv_state_var,
2551                                             psyc_recv_state_result, opcls);
2552       break;
2553
2554   default:
2555       GNUNET_assert (0);
2556   }
2557
2558   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2559 }
2560
2561
2562 static void
2563 namestore_recv_records_store_result (void *cls, int32_t result,
2564                                      const char *err_msg)
2565 {
2566   struct OperationClosure *ocls = cls;
2567   client_send_result (ocls->client, ocls->op_id, result, err_msg,
2568                       (NULL != err_msg) ? strlen (err_msg) : 0);
2569   GNUNET_free (ocls);
2570 }
2571
2572
2573 /**
2574  * Handle request to add PLACE record to GNS zone.
2575  */
2576 static void
2577 client_recv_zone_add_place (void *cls, struct GNUNET_SERVER_Client *client,
2578                              const struct GNUNET_MessageHeader *msg)
2579 {
2580   const struct ZoneAddPlaceRequest *preq
2581     = (const struct ZoneAddPlaceRequest *) msg;
2582
2583   uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
2584   const char *p = (const char *) &preq[1];
2585   const char *name = NULL, *password = NULL;
2586   uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
2587                                                     &name, &password);
2588   remaining -= offset;
2589   p += offset;
2590   const struct GNUNET_PeerIdentity *
2591     relays = (const struct GNUNET_PeerIdentity *) p;
2592   uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
2593
2594   if (0 == offset || remaining != relay_size)
2595   {
2596     GNUNET_break (0);
2597     client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2598     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2599     return;
2600   }
2601
2602   struct GNUNET_GNSRECORD_Data rd = { };
2603   rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
2604   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2605   rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
2606
2607   struct GNUNET_GNSRECORD_PlaceData *
2608     rec = GNUNET_malloc (sizeof (*rec) + relay_size);
2609   rec->place_pub_key = preq->place_pub_key;
2610   rec->origin = this_peer;
2611   rec->relay_count = preq->relay_count;
2612   memcpy (&rec[1], relays, relay_size);
2613
2614   rd.data = rec;
2615   rd.data_size = sizeof (*rec) + relay_size;
2616
2617   struct GNUNET_HashCode ego_pub_hash;
2618   GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash);
2619   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2620   if (NULL == ego)
2621   {
2622     client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
2623   }
2624   else
2625   {
2626     struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
2627     ocls->client = client;
2628     ocls->op_id = preq->op_id;
2629     GNUNET_NAMESTORE_records_store (namestore, &ego->key,
2630                                     name, 1, &rd,
2631                                     namestore_recv_records_store_result, ocls);
2632   }
2633   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2634 }
2635
2636
2637 /**
2638  * Handle request to add PLACE record to GNS zone.
2639  */
2640 static void
2641 client_recv_zone_add_nym (void *cls, struct GNUNET_SERVER_Client *client,
2642                           const struct GNUNET_MessageHeader *msg)
2643 {
2644   const struct ZoneAddNymRequest *nreq
2645     = (const struct ZoneAddNymRequest *) msg;
2646
2647   uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
2648   const char *name = NULL;
2649   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
2650                                                     name_size, 1, &name);
2651   if (0 == offset || offset != name_size)
2652   {
2653     GNUNET_break (0);
2654     client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
2655     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2656     return;
2657   }
2658
2659   struct GNUNET_GNSRECORD_Data rd = { };
2660   rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
2661   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2662   rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
2663   rd.data = &nreq->nym_pub_key;
2664   rd.data_size = sizeof (nreq->nym_pub_key);
2665
2666   struct GNUNET_HashCode ego_pub_hash;
2667   GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash);
2668   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2669   if (NULL == ego)
2670   {
2671     client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
2672   }
2673   else
2674   {
2675     struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
2676     ocls->client = client;
2677     ocls->op_id = nreq->op_id;
2678     GNUNET_NAMESTORE_records_store (namestore, &ego->key,
2679                                       name, 1, &rd,
2680                                       namestore_recv_records_store_result, ocls);
2681   }
2682   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2683 }
2684
2685
2686 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2687   { &client_recv_host_enter, NULL,
2688     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
2689
2690   { &client_recv_guest_enter, NULL,
2691     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
2692
2693   { &client_recv_guest_enter_by_name, NULL,
2694     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, 0 },
2695
2696   { &client_recv_join_decision, NULL,
2697     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
2698
2699   { &client_recv_psyc_message, NULL,
2700     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 },
2701
2702   { &client_recv_history_replay, NULL,
2703     GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, 0 },
2704
2705   { &client_recv_state_get, NULL,
2706     GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, 0 },
2707
2708   { &client_recv_state_get, NULL,
2709     GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
2710
2711   { &client_recv_zone_add_place, NULL,
2712     GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, 0 },
2713
2714   { &client_recv_zone_add_nym, NULL,
2715     GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, 0 },
2716
2717   { &client_recv_app_connect, NULL,
2718     GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, 0 },
2719
2720   { &client_recv_app_detach, NULL,
2721     GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, 0 },
2722
2723   { &client_recv_place_leave, NULL,
2724     GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, 0 },
2725
2726   { NULL, NULL, 0, 0 }
2727 };
2728
2729
2730 const char *
2731 path_basename (const char *path)
2732 {
2733   const char *basename = strrchr (path, DIR_SEPARATOR);
2734   if (NULL != basename)
2735     basename++;
2736
2737   if (NULL == basename || '\0' == basename)
2738     return NULL;
2739
2740   return basename;
2741 }
2742
2743
2744 struct PlaceLoadClosure
2745 {
2746   const char *app_id;
2747   const char *ego_pub_hash_str;
2748 };
2749
2750
2751 /** Load a place file */
2752 int
2753 file_place_load (void *cls, const char *filename)
2754 {
2755   char *app_id = cls;
2756   uint64_t file_size = 0;
2757   if (GNUNET_OK !=
2758       GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
2759       || file_size < sizeof (struct HostEnterRequest))
2760     return GNUNET_OK;
2761
2762   struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
2763   ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
2764   if (read_size < 0 || read_size < sizeof (*ereq))
2765     return GNUNET_OK;
2766
2767   uint16_t ereq_size = ntohs (ereq->header.size);
2768   if (read_size != ereq_size)
2769     return GNUNET_OK;
2770
2771   switch (ntohs (ereq->header.type))
2772   {
2773   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
2774     if (ereq_size < sizeof (struct HostEnterRequest))
2775       return GNUNET_OK;
2776     struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
2777     host_enter (hreq, NULL);
2778     break;
2779
2780   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
2781     if (ereq_size < sizeof (struct GuestEnterRequest))
2782       return GNUNET_OK;
2783     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
2784     guest_enter (greq, NULL);
2785     break;
2786
2787   default:
2788     return GNUNET_OK;
2789   }
2790
2791   app_place_add (app_id, ereq);
2792   return GNUNET_OK;
2793 }
2794
2795
2796 /** Load an ego place file */
2797 int
2798 file_ego_place_load (void *cls, const char *place_filename)
2799 {
2800   struct PlaceLoadClosure *plcls = cls;
2801
2802   const char *place_pub_hash_str = path_basename (place_filename);
2803   if (NULL == place_pub_hash_str)
2804   {
2805     GNUNET_break (0);
2806     return GNUNET_OK;
2807   }
2808
2809   char *filename = NULL;
2810   GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
2811                    dir_social, DIR_SEPARATOR,
2812                    "places", DIR_SEPARATOR,
2813                    plcls->ego_pub_hash_str, DIR_SEPARATOR,
2814                    place_pub_hash_str);
2815
2816   struct PlaceEnterRequest ereq[GNUNET_SERVER_MAX_MESSAGE_SIZE];
2817
2818   int read_size = GNUNET_DISK_fn_read (filename, &ereq,
2819                                        GNUNET_SERVER_MAX_MESSAGE_SIZE);
2820   GNUNET_free (filename);
2821
2822   if (read_size < (ssize_t) sizeof (ereq))
2823     return GNUNET_OK;
2824
2825   app_place_add (plcls->app_id, ereq);
2826   return GNUNET_OK;
2827 }
2828
2829
2830 /**
2831  * Read @e place_pub_hash_str entries in @a dir_ego
2832  *
2833  * @param dir_ego
2834  *        Data directory of an application ego.
2835  *        e.g. ~/.local/share/gnunet/social/apps/$app_id/$ego_pub_hash_str/
2836  */
2837 int
2838 scan_app_ego_dir (void *cls, const char *dir_ego)
2839 {
2840   struct PlaceLoadClosure *plcls = cls;
2841   plcls->ego_pub_hash_str = path_basename (dir_ego);
2842
2843   if (NULL != plcls->ego_pub_hash_str)
2844     GNUNET_DISK_directory_scan (dir_ego, file_ego_place_load, plcls);
2845
2846   return GNUNET_OK;
2847 }
2848
2849 /**
2850  * Read @e ego_pub_hash_str entries in @a dir_app
2851  *
2852  * @param dir_app
2853  *        Data directory of an application.
2854  *        e.g. ~/.local/share/gnunet/social/apps/$app_id/
2855  */
2856 int
2857 scan_app_dir (void *cls, const char *dir_app)
2858 {
2859   if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
2860     return GNUNET_OK;
2861
2862   struct PlaceLoadClosure plcls;
2863   plcls.app_id = path_basename (dir_app);
2864
2865   if (NULL != plcls.app_id)
2866     GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
2867
2868   return GNUNET_OK;
2869 }
2870
2871
2872 static void
2873 identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
2874                    void **ctx, const char *name)
2875 {
2876   if (NULL == id_ego) // end of initial list of egos
2877     return;
2878
2879   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
2880   GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
2881
2882   struct GNUNET_HashCode ego_pub_hash;
2883   GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
2884
2885   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
2886   if (NULL != ego)
2887   {
2888     GNUNET_free (ego->name);
2889     if (NULL == name) // deleted
2890     {
2891       GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
2892       GNUNET_free (ego);
2893       ego = NULL;
2894     }
2895   }
2896   else
2897   {
2898     ego = GNUNET_malloc (sizeof (*ego));
2899   }
2900   if (NULL != ego)
2901   {
2902     ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
2903     size_t name_size = strlen (name) + 1;
2904     ego->name = GNUNET_malloc (name_size);
2905     memcpy (ego->name, name, name_size);
2906
2907     GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
2908                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2909   }
2910 }
2911
2912
2913 /**
2914  * Connected to core service.
2915  */
2916 static void
2917 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
2918 {
2919   this_peer = *my_identity;
2920 }
2921
2922
2923 /**
2924  * Initialize the PSYC service.
2925  *
2926  * @param cls Closure.
2927  * @param server The initialized server.
2928  * @param c Configuration to use.
2929  */
2930 static void
2931 run (void *cls, struct GNUNET_SERVER_Handle *server,
2932      const struct GNUNET_CONFIGURATION_Handle *c)
2933 {
2934   cfg = c;
2935
2936   hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2937   guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2938   place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2939
2940   egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2941   apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2942   places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
2943   apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
2944
2945   core = GNUNET_CORE_connect (cfg, NULL, core_connected, NULL, NULL,
2946                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
2947   id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
2948   gns = GNUNET_GNS_connect (cfg);
2949   namestore = GNUNET_NAMESTORE_connect (cfg);
2950   stats = GNUNET_STATISTICS_create ("social", cfg);
2951
2952   if (GNUNET_OK !=
2953       GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "SOCIAL_DATA_DIR",
2954                                                &dir_social))
2955   {
2956     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2957                                "social", "SOCIAL_DATA_DIR");
2958     GNUNET_break (0);
2959     return;
2960   }
2961   GNUNET_asprintf (&dir_places, "%s%c%s",
2962                    dir_social, DIR_SEPARATOR, "places");
2963   GNUNET_asprintf (&dir_apps, "%s%c%s",
2964                    dir_social, DIR_SEPARATOR, "apps");
2965
2966   GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
2967
2968   nc = GNUNET_SERVER_notification_context_create (server, 1);
2969   GNUNET_SERVER_add_handlers (server, handlers);
2970   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
2971   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2972                                 &shutdown_task, NULL);
2973 }
2974
2975
2976 /**
2977  * The main function for the service.
2978  *
2979  * @param argc number of arguments from the command line
2980  * @param argv command line arguments
2981  * @return 0 ok, 1 on error
2982  */
2983 int
2984 main (int argc, char *const *argv)
2985 {
2986   return (GNUNET_OK ==
2987           GNUNET_SERVICE_run (argc, argv, "social",
2988                               GNUNET_SERVICE_OPTION_NONE,
2989                               &run, NULL)) ? 0 : 1;
2990 }
2991
2992 /* end of gnunet-service-social.c */