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