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