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