More API function tests...
[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, &greq->ego_pub_key,
1959                      GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1960                      NULL, gns_result_guest_enter, gcls);
1961 }
1962
1963
1964 void
1965 app_notify_place (struct GNUNET_MessageHeader *msg,
1966                   struct GNUNET_SERVICE_Client *client)
1967 {
1968   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1969               "%p Sending place notification of type %u to client.\n",
1970               client, ntohs (msg->type));
1971
1972   uint16_t msg_size = ntohs (msg->size);
1973   struct AppPlaceMessage amsg;
1974   amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1975   amsg.header.size = htons (sizeof (amsg));
1976   // FIXME: also notify about not entered places
1977   amsg.place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED;
1978
1979   switch (ntohs (msg->type))
1980   {
1981   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1982     if (msg_size < sizeof (struct HostEnterRequest))
1983       return;
1984     struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1985     amsg.is_host = GNUNET_YES;
1986     amsg.ego_pub_key = hreq->ego_pub_key;
1987     amsg.place_pub_key = hreq->place_pub_key;
1988     break;
1989
1990   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1991     if (msg_size < sizeof (struct GuestEnterRequest))
1992       return;
1993     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1994     amsg.is_host = GNUNET_NO;
1995     amsg.ego_pub_key = greq->ego_pub_key;
1996     amsg.place_pub_key = greq->place_pub_key;
1997     break;
1998
1999   default:
2000     return;
2001   }
2002
2003   client_send_msg (client, &amsg.header);
2004 }
2005
2006
2007 void
2008 app_notify_place_end (struct GNUNET_SERVICE_Client *client)
2009 {
2010   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2011               "%p Sending end of place list notification to client\n",
2012               client);
2013
2014   struct GNUNET_MessageHeader msg;
2015   msg.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END);
2016   msg.size = htons (sizeof (msg));
2017
2018   client_send_msg (client, &msg);
2019 }
2020
2021
2022 void
2023 app_notify_ego (struct Ego *ego, struct GNUNET_SERVICE_Client *client)
2024 {
2025   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2026               "%p Sending ego notification to client: %s\n",
2027               client, ego->name);
2028
2029   size_t name_size = strlen (ego->name) + 1;
2030   struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size);
2031   emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
2032   emsg->header.size = htons (sizeof (*emsg) + name_size);
2033
2034   GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
2035   GNUNET_memcpy (&emsg[1], ego->name, name_size);
2036
2037   client_send_msg (client, &emsg->header);
2038   GNUNET_free (emsg);
2039 }
2040
2041
2042 void
2043 app_notify_ego_end (struct GNUNET_SERVICE_Client *client)
2044 {
2045   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2046               "%p Sending end of ego list notification to client\n",
2047               client);
2048
2049   struct GNUNET_MessageHeader msg;
2050   msg.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END);
2051   msg.size = htons (sizeof (msg));
2052
2053   client_send_msg (client, &msg);
2054 }
2055
2056
2057 int
2058 app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value)
2059 {
2060   struct GNUNET_MessageHeader *
2061     msg = GNUNET_CONTAINER_multihashmap_get (places, key);
2062   if (NULL != msg)
2063     app_notify_place (msg, cls);
2064   return GNUNET_YES;
2065 }
2066
2067
2068 int
2069 ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
2070 {
2071   app_notify_ego (value, cls);
2072   return GNUNET_YES;
2073 }
2074
2075
2076 static int
2077 check_client_app_connect (void *cls,
2078                           const struct AppConnectRequest *creq)
2079 {
2080   return GNUNET_OK;
2081 }
2082
2083
2084 /**
2085  * Handle application connection.
2086  */
2087 static void
2088 handle_client_app_connect (void *cls,
2089                            const struct AppConnectRequest *creq)
2090 {
2091   struct Client *c = cls;
2092   struct GNUNET_SERVICE_Client *client = c->client;
2093
2094   uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
2095   const char *app_id = NULL;
2096   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
2097                                                     app_id_size, 1, &app_id);
2098   if (0 == offset || offset != app_id_size)
2099   {
2100     GNUNET_break (0);
2101     GNUNET_SERVICE_client_drop (client);
2102     return;
2103   }
2104
2105   struct GNUNET_HashCode app_id_hash;
2106   GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash);
2107
2108   GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
2109   app_notify_ego_end (client);
2110
2111   struct GNUNET_CONTAINER_MultiHashMap *
2112     app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
2113   if (NULL != app_places)
2114     GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client);
2115   app_notify_place_end (client);
2116
2117   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
2118   cli->client = client;
2119   struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
2120                                                                &app_id_hash);
2121   if (NULL == app) {
2122     app = GNUNET_malloc (sizeof (*app));
2123     (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
2124                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2125   }
2126   GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
2127
2128   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2129               "%p Application %s connected.\n", app, app_id);
2130
2131   c->app_id = GNUNET_malloc (app_id_size);
2132   GNUNET_memcpy (c->app_id, app_id, app_id_size);
2133
2134   GNUNET_SERVICE_client_continue (client);
2135 }
2136
2137
2138 /**
2139  * Handle application detach request.
2140  */
2141 static void
2142 handle_client_app_detach (void *cls,
2143                           const struct AppDetachRequest *req)
2144 {
2145   struct Client *c = cls;
2146   struct GNUNET_SERVICE_Client *client = c->client;
2147
2148   int ret = app_place_remove (c->app_id, &req->ego_pub_key, &req->place_pub_key);
2149   client_send_result (client, req->op_id, ret, NULL, 0);
2150
2151   GNUNET_SERVICE_client_continue (client);
2152 }
2153
2154
2155 int
2156 app_places_entry_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
2157 {
2158   struct Place *plc = cls;
2159   const char *app_id = value;
2160   app_place_remove (app_id, &plc->ego_pub_key, &plc->pub_key);
2161   return GNUNET_YES;
2162 }
2163
2164
2165 /**
2166  * Handle application leave request.
2167  */
2168 static void
2169 handle_client_place_leave (void *cls,
2170                            const struct GNUNET_MessageHeader *msg)
2171 {
2172   struct Client *c = cls;
2173   struct GNUNET_SERVICE_Client *client = c->client;
2174   struct Place *plc = c->place;
2175   if (NULL == plc)
2176   {
2177     GNUNET_break (0);
2178     GNUNET_SERVICE_client_drop (client);
2179     return;
2180   }
2181
2182   /* FIXME: remove all app subscriptions and leave this place  */
2183
2184   struct GNUNET_CONTAINER_MultiHashMap *
2185     place_apps = GNUNET_CONTAINER_multihashmap_get (places_apps, &plc->pub_key_hash);
2186   if (NULL != place_apps)
2187   {
2188     GNUNET_CONTAINER_multihashmap_iterate (place_apps, app_places_entry_remove, plc);
2189   }
2190
2191   /* FIXME: disconnect from the network, but keep local connection for history access */
2192
2193   /* Disconnect all clients connected to the place */
2194   struct ClientListItem *cli = plc->clients_head, *next;
2195   while (NULL != cli)
2196   {
2197     GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
2198     GNUNET_SERVICE_client_drop (cli->client);
2199     next = cli->next;
2200     GNUNET_free (cli);
2201     cli = next;
2202   }
2203
2204   if (GNUNET_YES != plc->is_disconnected)
2205   {
2206     plc->is_disconnected = GNUNET_YES;
2207     if (NULL != plc->tmit_msgs_head)
2208     { /* Send pending messages to PSYC before cleanup. */
2209       psyc_transmit_message (plc);
2210     }
2211     else
2212     {
2213       cleanup_place (plc);
2214     }
2215   }
2216 }
2217
2218
2219 struct JoinDecisionClosure
2220 {
2221   int32_t is_admitted;
2222   struct GNUNET_PSYC_Message *msg;
2223 };
2224
2225
2226 /**
2227  * Iterator callback for responding to join requests.
2228  */
2229 static int
2230 psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
2231                          void *value)
2232 {
2233   struct JoinDecisionClosure *jcls = cls;
2234   struct GNUNET_PSYC_JoinHandle *jh = value;
2235   // FIXME: add relays
2236   GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
2237   return GNUNET_YES;
2238 }
2239
2240
2241 static int
2242 check_client_join_decision (void *cls,
2243                             const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
2244 {
2245   return GNUNET_OK;
2246 }
2247
2248
2249 /**
2250  * Handle an entry decision from a host client.
2251  */
2252 static void
2253 handle_client_join_decision (void *cls,
2254                              const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
2255 {
2256   struct Client *c = cls;
2257   struct GNUNET_SERVICE_Client *client = c->client;
2258   struct Place *plc = c->place;
2259   if (NULL == plc || GNUNET_YES != plc->is_host)
2260   {
2261     GNUNET_break (0);
2262     GNUNET_SERVICE_client_drop (client);
2263     return;
2264   }
2265   struct Host *hst = plc->host;
2266
2267   struct JoinDecisionClosure jcls;
2268   jcls.is_admitted = ntohl (dcsn->is_admitted);
2269   jcls.msg
2270     = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size))
2271     ? (struct GNUNET_PSYC_Message *) &dcsn[1]
2272     : NULL;
2273
2274   struct GNUNET_HashCode slave_pub_hash;
2275   GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key),
2276                       &slave_pub_hash);
2277
2278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2279               "%p Got join decision (%d) from client for place %s..\n",
2280               hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
2281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282               "%p ..and slave %s.\n",
2283               hst, GNUNET_h2s (&slave_pub_hash));
2284
2285   GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_pub_hash,
2286                                               &psyc_send_join_decision, &jcls);
2287   GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_pub_hash);
2288
2289   GNUNET_SERVICE_client_continue (client);
2290 }
2291
2292
2293 /**
2294  * Send acknowledgement to a client.
2295  *
2296  * Sent after a message fragment has been passed on to multicast.
2297  *
2298  * @param plc The place struct for the client.
2299  */
2300 static void
2301 send_message_ack (struct Place *plc, struct GNUNET_SERVICE_Client *client)
2302 {
2303   struct GNUNET_MessageHeader res;
2304   res.size = htons (sizeof (res));
2305   res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
2306   client_send_msg (client, &res);
2307 }
2308
2309
2310 /**
2311  * Proceed to the next message part in the transmission queue.
2312  *
2313  * @param plc
2314  *        Place where the transmission is going on.
2315  * @param tmit_msg
2316  *        Currently transmitted message.
2317  * @param tmit_frag
2318  *        Currently transmitted message fragment.
2319  *
2320  * @return @a tmit_frag, or NULL if reached the end of fragment.
2321  */
2322 static struct FragmentTransmitQueue *
2323 psyc_transmit_queue_next_part (struct Place *plc,
2324                                struct MessageTransmitQueue *tmit_msg,
2325                                struct FragmentTransmitQueue *tmit_frag)
2326 {
2327   uint16_t psize = ntohs (tmit_frag->next_part->size);
2328   if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
2329       < tmit_frag->size)
2330   {
2331     tmit_frag->next_part
2332       = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
2333   }
2334   else /* Reached end of current fragment. */
2335   {
2336     if (NULL != tmit_frag->client)
2337       send_message_ack (plc, tmit_frag->client);
2338     GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2339     GNUNET_free (tmit_frag);
2340     tmit_frag = NULL;
2341   }
2342   return tmit_frag;
2343 }
2344
2345
2346 /**
2347  * Proceed to next message in transmission queue.
2348  *
2349  * @param plc
2350  *        Place where the transmission is going on.
2351  * @param tmit_msg
2352  *        Currently transmitted message.
2353  *
2354  * @return The next message in queue, or NULL if queue is empty.
2355  */
2356 static struct MessageTransmitQueue *
2357 psyc_transmit_queue_next_msg (struct Place *plc,
2358                               struct MessageTransmitQueue *tmit_msg)
2359 {
2360   GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2361   GNUNET_free (tmit_msg);
2362   return plc->tmit_msgs_head;
2363 }
2364
2365
2366 /**
2367  * Callback for data transmission to PSYC.
2368  */
2369 static int
2370 psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2371 {
2372   struct Place *plc = cls;
2373   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2374   GNUNET_assert (NULL != tmit_msg);
2375   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2376   if (NULL == tmit_frag)
2377   { /* Rest of the message have not arrived yet, pause transmission */
2378     *data_size = 0;
2379     return GNUNET_NO;
2380   }
2381   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2382   if (NULL == pmsg)
2383   {
2384     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2385                 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
2386     *data_size = 0;
2387     return GNUNET_NO;
2388   }
2389
2390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2391               "%p psyc_transmit_notify_data()\n", plc);
2392   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2393
2394   uint16_t ptype = ntohs (pmsg->type);
2395   uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
2396   int ret;
2397
2398   switch (ptype)
2399   {
2400   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2401     if (*data_size < pdata_size)
2402     {
2403       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2404                 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
2405       *data_size = 0;
2406       return GNUNET_NO;
2407     }
2408     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2409                 "%p psyc_transmit_notify_data: sending %u bytes.\n",
2410                 plc, pdata_size);
2411
2412     *data_size = pdata_size;
2413     GNUNET_memcpy (data, &pmsg[1], *data_size);
2414     ret = GNUNET_NO;
2415     break;
2416
2417   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2418     *data_size = 0;
2419     ret = GNUNET_YES;
2420     break;
2421
2422   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2423     *data_size = 0;
2424     ret = GNUNET_SYSERR;
2425     break;
2426
2427   default:
2428     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2429                 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
2430                 plc, ptype);
2431     ret = GNUNET_SYSERR;
2432   }
2433
2434   if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
2435   {
2436     *data_size = 0;
2437     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2438     plc->is_disconnected = GNUNET_YES;
2439     GNUNET_SERVICE_client_drop (tmit_frag->client);
2440     GNUNET_SCHEDULER_add_now (&cleanup_place, plc);
2441     return ret;
2442   }
2443   else
2444   {
2445     tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2446     if (NULL != tmit_frag)
2447     {
2448       struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2449       ptype = ntohs (pmsg->type);
2450       switch (ptype)
2451       {
2452       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2453         ret = GNUNET_YES;
2454         break;
2455       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2456         ret = GNUNET_SYSERR;
2457         break;
2458       }
2459       switch (ptype)
2460       {
2461       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2462       case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2463         tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2464       }
2465     }
2466
2467     if (NULL == tmit_msg->frags_head
2468         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2469     { /* Reached end of current message. */
2470       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2471     }
2472   }
2473
2474   if (ret != GNUNET_NO)
2475   {
2476     if (NULL != tmit_msg)
2477     {
2478       psyc_transmit_message (plc);
2479     }
2480     else if (GNUNET_YES == plc->is_disconnected)
2481     {
2482       /* FIXME: handle partial message (when still in_transmit) */
2483       cleanup_place (plc);
2484     }
2485   }
2486   return ret;
2487 }
2488
2489
2490 /**
2491  * Callback for modifier transmission to PSYC.
2492  */
2493 static int
2494 psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2495                           uint8_t *oper, uint32_t *full_value_size)
2496 {
2497   struct Place *plc = cls;
2498   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2499   GNUNET_assert (NULL != tmit_msg);
2500   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2501   if (NULL == tmit_frag)
2502   { /* Rest of the message have not arrived yet, pause transmission */
2503     *data_size = 0;
2504     return GNUNET_NO;
2505   }
2506   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2507   if (NULL == pmsg)
2508   {
2509     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2510                 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
2511     *data_size = 0;
2512     return GNUNET_NO;
2513   }
2514
2515   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2516               "%p psyc_transmit_notify_mod()\n", plc);
2517   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2518
2519   uint16_t ptype = ntohs (pmsg->type);
2520   int ret;
2521
2522   switch (ptype)
2523   {
2524   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
2525   {
2526     if (NULL == oper)
2527     {
2528       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2529                   "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
2530       ret = GNUNET_SYSERR;
2531       break;
2532     }
2533     struct GNUNET_PSYC_MessageModifier *
2534       pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
2535     uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
2536
2537     if (*data_size < mod_size)
2538     {
2539       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2540                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2541       *data_size = 0;
2542       return GNUNET_NO;
2543     }
2544
2545     *full_value_size = ntohl (pmod->value_size);
2546     *oper = pmod->oper;
2547     *data_size = mod_size;
2548     GNUNET_memcpy (data, &pmod[1], mod_size);
2549     ret = GNUNET_NO;
2550     break;
2551   }
2552
2553   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
2554   {
2555     if (NULL != oper)
2556     {
2557       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2558                   "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
2559       ret = GNUNET_SYSERR;
2560       break;
2561     }
2562     uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
2563     if (*data_size < mod_size)
2564     {
2565       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2566                 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2567       *data_size = 0;
2568       return GNUNET_NO;
2569     }
2570     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2571                 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
2572
2573     *data_size = mod_size;
2574     GNUNET_memcpy (data, &pmsg[1], *data_size);
2575     ret = GNUNET_NO;
2576     break;
2577   }
2578
2579   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2580   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2581   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2582     *data_size = 0;
2583     ret = GNUNET_YES;
2584     break;
2585
2586   default:
2587     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2588                 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
2589                 plc, ptype);
2590     ret = GNUNET_SYSERR;
2591   }
2592
2593   if (GNUNET_SYSERR == ret)
2594   {
2595     *data_size = 0;
2596     ret = GNUNET_SYSERR;
2597     tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2598     plc->is_disconnected = GNUNET_YES;
2599     GNUNET_SERVICE_client_drop (tmit_frag->client);
2600     GNUNET_SCHEDULER_add_now (&cleanup_place, plc);
2601   }
2602   else
2603   {
2604     if (GNUNET_YES != ret)
2605       psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2606
2607     if (NULL == tmit_msg->frags_head
2608         && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2609     { /* Reached end of current message. */
2610       tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2611     }
2612   }
2613   return ret;
2614 }
2615
2616 /**
2617  * Callback for data transmission from a host to PSYC.
2618  */
2619 static int
2620 host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2621 {
2622   int ret = psyc_transmit_notify_data (cls, data_size, data);
2623
2624   if (GNUNET_NO != ret)
2625   {
2626     struct Host *hst = cls;
2627     hst->tmit_handle = NULL;
2628   }
2629   return ret;
2630 }
2631
2632
2633 /**
2634  * Callback for the transmit functions of multicast.
2635  */
2636 static int
2637 guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2638 {
2639   int ret = psyc_transmit_notify_data (cls, data_size, data);
2640
2641   if (GNUNET_NO != ret)
2642   {
2643     struct Guest *gst = cls;
2644     gst->tmit_handle = NULL;
2645   }
2646   return ret;
2647 }
2648
2649
2650 /**
2651  * Callback for modifier transmission from a host to PSYC.
2652  */
2653 static int
2654 host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2655                           uint8_t *oper, uint32_t *full_value_size)
2656 {
2657   int ret = psyc_transmit_notify_mod (cls, data_size, data,
2658                                       oper, full_value_size);
2659   if (GNUNET_SYSERR == ret)
2660   {
2661     struct Host *hst = cls;
2662     hst->tmit_handle = NULL;
2663   }
2664   return ret;
2665 }
2666
2667
2668 /**
2669  * Callback for modifier transmission from a guest to PSYC.
2670  */
2671 static int
2672 guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2673                            uint8_t *oper, uint32_t *full_value_size)
2674 {
2675   int ret = psyc_transmit_notify_mod (cls, data_size, data,
2676                                       oper, full_value_size);
2677   if (GNUNET_SYSERR == ret)
2678   {
2679     struct Guest *gst = cls;
2680     gst->tmit_handle = NULL;
2681   }
2682   return ret;
2683 }
2684
2685
2686 /**
2687  * Get method part of next message from transmission queue.
2688  *
2689  * @param plc
2690  *        Place
2691  *
2692  * @return #GNUNET_OK on success
2693  *         #GNUNET_NO if there are no more messages in queue.
2694  *         #GNUNET_SYSERR if the next message is malformed.
2695  */
2696 static struct GNUNET_PSYC_MessageMethod *
2697 psyc_transmit_queue_next_method (struct Place *plc)
2698 {
2699   struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2700   if (NULL == tmit_msg)
2701     return GNUNET_NO;
2702
2703   struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2704   if (NULL == tmit_frag)
2705   {
2706     GNUNET_break (0);
2707     return GNUNET_NO;
2708   }
2709
2710   struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2711   if (NULL == pmsg
2712       || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
2713   {
2714     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2715                 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
2716                 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
2717     GNUNET_break (0);
2718     return NULL;
2719   }
2720
2721   uint16_t psize = ntohs (pmsg->size);
2722   struct GNUNET_PSYC_MessageMethod *
2723     pmeth = (struct GNUNET_PSYC_MessageMethod *) GNUNET_copy_message (pmsg);
2724
2725   if (psize < sizeof (*pmeth) + 1 || '\0' != *((char *) pmeth + psize - 1))
2726   {
2727     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2728                 "%p psyc_transmit_queue_next_method: invalid method name.\n",
2729                 plc);
2730     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2731                 "%zu <= %u || NUL != %u\n",
2732                 sizeof (*pmeth), psize, *((char *) pmeth + psize - 1));
2733     GNUNET_break (0);
2734     GNUNET_free (pmeth);
2735     return NULL;
2736   }
2737
2738   psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2739   return pmeth;
2740 }
2741
2742
2743 /**
2744  * Transmit the next message in queue from the host to the PSYC channel.
2745  */
2746 static int
2747 psyc_master_transmit_message (struct Host *hst)
2748 {
2749   struct Place *plc = &hst->place;
2750
2751   if (NULL == hst->tmit_handle)
2752   {
2753     struct GNUNET_PSYC_MessageMethod *
2754       pmeth = psyc_transmit_queue_next_method (plc);
2755     if (NULL == pmeth)
2756       return GNUNET_SYSERR;
2757
2758     hst->tmit_handle = (void *) &hst->tmit_handle;
2759     struct GNUNET_PSYC_MasterTransmitHandle *
2760       tmit_handle = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
2761                                                  &host_transmit_notify_mod,
2762                                                  &host_transmit_notify_data, hst,
2763                                                  pmeth->flags);
2764     if (NULL != hst->tmit_handle)
2765       hst->tmit_handle = tmit_handle;
2766     GNUNET_free (pmeth);
2767   }
2768   else
2769   {
2770     GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
2771   }
2772   return GNUNET_OK;
2773 }
2774
2775
2776 /**
2777  * Transmit the next message in queue from a guest to the PSYC channel.
2778  */
2779 static int
2780 psyc_slave_transmit_message (struct Guest *gst)
2781 {
2782   struct Place *plc = &gst->place;
2783
2784   if (NULL == gst->tmit_handle)
2785   {
2786     struct GNUNET_PSYC_MessageMethod *
2787       pmeth = psyc_transmit_queue_next_method (plc);
2788     if (NULL == pmeth)
2789       return GNUNET_SYSERR;
2790
2791     gst->tmit_handle = (void *) &gst->tmit_handle;
2792     struct GNUNET_PSYC_SlaveTransmitHandle *
2793       tmit_handle = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
2794                                                  &guest_transmit_notify_mod,
2795                                                  &guest_transmit_notify_data, gst,
2796                                                  pmeth->flags);
2797     if (NULL != gst->tmit_handle)
2798       gst->tmit_handle = tmit_handle;
2799     GNUNET_free (pmeth);
2800   }
2801   else
2802   {
2803     GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
2804   }
2805   return GNUNET_OK;
2806 }
2807
2808
2809 /**
2810  * Transmit a message to PSYC.
2811  */
2812 static int
2813 psyc_transmit_message (struct Place *plc)
2814 {
2815   return
2816     (plc->is_host)
2817     ? psyc_master_transmit_message ((struct Host *) plc)
2818     : psyc_slave_transmit_message ((struct Guest *) plc);
2819 }
2820
2821
2822 /**
2823  * Queue message parts for sending to PSYC.
2824  *
2825  * @param plc          Place to send to.
2826  * @param client       Client the message originates from.
2827  * @param data_size    Size of @a data.
2828  * @param data         Concatenated message parts.
2829  * @param first_ptype  First message part type in @a data.
2830  * @param last_ptype   Last message part type in @a data.
2831  */
2832 static struct MessageTransmitQueue *
2833 psyc_transmit_queue_message (struct Place *plc,
2834                              struct GNUNET_SERVICE_Client *client,
2835                              size_t data_size,
2836                              const void *data,
2837                              uint16_t first_ptype, uint16_t last_ptype,
2838                              struct MessageTransmitQueue *tmit_msg)
2839 {
2840   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
2841   {
2842     tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
2843     GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2844   }
2845   else if (NULL == tmit_msg)
2846   {
2847     return NULL;
2848   }
2849
2850   struct FragmentTransmitQueue *
2851     tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
2852   GNUNET_memcpy (&tmit_frag[1], data, data_size);
2853   tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
2854   tmit_frag->client = client;
2855   tmit_frag->size = data_size;
2856
2857   GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2858   tmit_msg->client = client;
2859   return tmit_msg;
2860 }
2861
2862
2863 /**
2864  * Cancel transmission of current message to PSYC.
2865  *
2866  * @param plc     Place to send to.
2867  * @param client  Client the message originates from.
2868  */
2869 static void
2870 psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVICE_Client *client)
2871 {
2872   uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2873
2874   struct GNUNET_MessageHeader msg;
2875   msg.size = htons (sizeof (msg));
2876   msg.type = htons (type);
2877
2878   psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
2879   psyc_transmit_message (plc);
2880
2881   /* FIXME: cleanup */
2882 }
2883
2884
2885 static int
2886 check_client_psyc_message (void *cls,
2887                            const struct GNUNET_MessageHeader *msg)
2888 {
2889   return GNUNET_OK;
2890 }
2891
2892
2893 /**
2894  * Handle an incoming message from a client, to be transmitted to the place.
2895  */
2896 static void
2897 handle_client_psyc_message (void *cls,
2898                             const struct GNUNET_MessageHeader *msg)
2899 {
2900   struct Client *c = cls;
2901   struct GNUNET_SERVICE_Client *client = c->client;
2902   struct Place *plc = c->place;
2903   if (NULL == plc)
2904   {
2905     GNUNET_break (0);
2906     GNUNET_SERVICE_client_drop (client);
2907     return;
2908   }
2909
2910   int ret = GNUNET_SYSERR;
2911
2912   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2913               "%p Received message from client.\n", plc);
2914   GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2915
2916   if (GNUNET_YES != plc->is_ready)
2917   {
2918     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2919                 "%p Place is not ready yet, disconnecting client.\n", plc);
2920     GNUNET_break (0);
2921     GNUNET_SERVICE_client_drop (client);
2922     return;
2923   }
2924
2925   uint16_t size = ntohs (msg->size);
2926   uint16_t psize = size - sizeof (*msg);
2927   if (psize < sizeof (struct GNUNET_MessageHeader)
2928       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
2929   {
2930     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2931                 "%p Received message with invalid payload size (%u) from client.\n",
2932                 plc, psize);
2933     GNUNET_break (0);
2934     psyc_transmit_cancel (plc, client);
2935     GNUNET_SERVICE_client_drop (client);
2936     return;
2937   }
2938
2939   uint16_t first_ptype = 0, last_ptype = 0;
2940   if (GNUNET_SYSERR
2941       == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
2942                                           &first_ptype, &last_ptype))
2943   {
2944     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2945                 "%p Received invalid message part from client.\n", plc);
2946     GNUNET_break (0);
2947     psyc_transmit_cancel (plc, client);
2948     GNUNET_SERVICE_client_drop (client);
2949     return;
2950   }
2951   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2952               "%p Received message with first part type %u and last part type %u.\n",
2953               plc, first_ptype, last_ptype);
2954
2955   c->tmit_msg
2956     = psyc_transmit_queue_message (plc, client, psize, &msg[1],
2957                                    first_ptype, last_ptype, c->tmit_msg);
2958   if (NULL != c->tmit_msg)
2959   {
2960     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
2961       c->tmit_msg = NULL;
2962     ret = psyc_transmit_message (plc);
2963   }
2964
2965   if (GNUNET_OK != ret)
2966   {
2967     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2968                 "%p Received invalid message part from client.\n", plc);
2969     GNUNET_break (0);
2970     psyc_transmit_cancel (plc, client);
2971     ret = GNUNET_SYSERR;
2972   }
2973
2974   if (GNUNET_OK == ret)
2975     GNUNET_SERVICE_client_continue (client);
2976   else
2977     GNUNET_SERVICE_client_drop (client);
2978 }
2979
2980
2981 /**
2982  * A historic message arrived from PSYC.
2983  */
2984 static void
2985 psyc_recv_history_message (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
2986 {
2987   struct OperationClosure *opcls = cls;
2988   struct Client *c = opcls->client;
2989   struct Place *plc = c->place;
2990
2991   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2992               "%p Received historic message #%" PRId64 " (flags: %x)\n",
2993               plc, GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
2994
2995   uint16_t size = ntohs (msg->header.size);
2996
2997   struct GNUNET_OperationResultMessage *
2998     res = GNUNET_malloc (sizeof (*res) + size);
2999   res->header.size = htons (sizeof (*res) + size);
3000   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
3001   res->op_id = opcls->op_id;
3002   res->result_code = GNUNET_htonll (GNUNET_OK);
3003
3004   GNUNET_memcpy (&res[1], msg, size);
3005
3006   /** @todo FIXME: send only to requesting client */
3007   place_send_msg (plc, &res->header);
3008
3009   GNUNET_free (res);
3010 }
3011
3012
3013 /**
3014  * Result of message history replay from PSYC.
3015  */
3016 static void
3017 psyc_recv_history_result (void *cls, int64_t result,
3018                           const void *err_msg, uint16_t err_msg_size)
3019 {
3020   struct OperationClosure *opcls = cls;
3021   struct Client *c = opcls->client;
3022   struct Place *plc = c->place;
3023
3024   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3025               "%p History replay #%" PRIu64 ": "
3026               "PSYCstore returned %" PRId64 " (%.*s)\n",
3027               plc, GNUNET_ntohll (opcls->op_id), result,
3028               err_msg_size, (const char *) err_msg);
3029
3030   // FIXME: place might have been destroyed
3031   client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size);
3032 }
3033
3034
3035 static int
3036 check_client_history_replay (void *cls,
3037                              const struct GNUNET_PSYC_HistoryRequestMessage *req)
3038 {
3039   return GNUNET_OK;
3040 }
3041
3042
3043 /**
3044  * Client requests channel history.
3045  */
3046 static void
3047 handle_client_history_replay (void *cls,
3048                               const struct GNUNET_PSYC_HistoryRequestMessage *req)
3049 {
3050   struct Client *c = cls;
3051   struct GNUNET_SERVICE_Client *client = c->client;
3052   struct Place *plc = c->place;
3053   if (NULL == plc)
3054   {
3055     GNUNET_break (0);
3056     GNUNET_SERVICE_client_drop (client);
3057     return;
3058   }
3059
3060   uint16_t size = ntohs (req->header.size);
3061   const char *method_prefix = (const char *) &req[1];
3062
3063   if (size < sizeof (*req) + 1
3064       || '\0' != method_prefix[size - sizeof (*req) - 1])
3065   {
3066     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3067                 "%p History replay #%" PRIu64 ": "
3068                 "invalid method prefix. size: %u < %zu?\n",
3069                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
3070     GNUNET_break (0);
3071     GNUNET_SERVICE_client_drop (client);
3072     return;
3073   }
3074
3075   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3076   opcls->client = c;
3077   opcls->op_id = req->op_id;
3078   opcls->flags = ntohl (req->flags);
3079
3080   if (0 == req->message_limit)
3081     GNUNET_PSYC_channel_history_replay (plc->channel,
3082                                         GNUNET_ntohll (req->start_message_id),
3083                                         GNUNET_ntohll (req->end_message_id),
3084                                         method_prefix, opcls->flags,
3085                                         psyc_recv_history_message, NULL,
3086                                         psyc_recv_history_result, opcls);
3087   else
3088     GNUNET_PSYC_channel_history_replay_latest (plc->channel,
3089                                                GNUNET_ntohll (req->message_limit),
3090                                                method_prefix, opcls->flags,
3091                                                psyc_recv_history_message, NULL,
3092                                                psyc_recv_history_result, opcls);
3093
3094   GNUNET_SERVICE_client_continue (client);
3095 }
3096
3097
3098 /**
3099  * A state variable part arrived from PSYC.
3100  */
3101 void
3102 psyc_recv_state_var (void *cls,
3103                      const struct GNUNET_MessageHeader *mod,
3104                      const char *name,
3105                      const void *value,
3106                      uint32_t value_size,
3107                      uint32_t full_value_size)
3108 {
3109   struct OperationClosure *opcls = cls;
3110   struct Client *c = opcls->client;
3111   struct Place *plc = c->place;
3112
3113   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3114               "%p Received state variable %s from PSYC\n",
3115               plc, name);
3116
3117   uint16_t size = ntohs (mod->size);
3118
3119   struct GNUNET_OperationResultMessage *
3120     res = GNUNET_malloc (sizeof (*res) + size);
3121   res->header.size = htons (sizeof (*res) + size);
3122   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
3123   res->op_id = opcls->op_id;
3124   res->result_code = GNUNET_htonll (GNUNET_OK);
3125
3126   GNUNET_memcpy (&res[1], mod, size);
3127
3128   /** @todo FIXME: send only to requesting client */
3129   place_send_msg (plc, &res->header);
3130
3131   GNUNET_free (res);
3132 }
3133
3134
3135 /**
3136  * Result of retrieving state variable from PSYC.
3137  */
3138 static void
3139 psyc_recv_state_result (void *cls, int64_t result,
3140                         const void *err_msg, uint16_t err_msg_size)
3141 {
3142   struct OperationClosure *opcls = cls;
3143   struct Client *c = opcls->client;
3144   struct Place *plc = c->place;
3145
3146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147               "%p State get #%" PRIu64 ": "
3148               "PSYCstore returned %" PRId64 " (%.*s)\n",
3149               plc, GNUNET_ntohll (opcls->op_id), result,
3150               err_msg_size, (const char *) err_msg);
3151
3152   // FIXME: place might have been destroyed
3153   client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size);
3154 }
3155
3156
3157 static int
3158 check_client_state_get (void *cls,
3159                         const struct GNUNET_PSYC_StateRequestMessage *req)
3160 {
3161   return GNUNET_OK;
3162 }
3163
3164
3165 /**
3166  * Client requests channel history.
3167  */
3168 static void
3169 handle_client_state_get (void *cls,
3170                          const struct GNUNET_PSYC_StateRequestMessage *req)
3171 {
3172   struct Client *c = cls;
3173   struct GNUNET_SERVICE_Client *client = c->client;
3174   struct Place *plc = c->place;
3175   if (NULL == plc)
3176   {
3177     GNUNET_break (0);
3178     GNUNET_SERVICE_client_drop (client);
3179     return;
3180   }
3181
3182   uint16_t size = ntohs (req->header.size);
3183   const char *name = (const char *) &req[1];
3184
3185   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3186               "%p State get #%" PRIu64 ": %s\n",
3187               plc, GNUNET_ntohll (req->op_id), name);
3188
3189   if (size < sizeof (*req) + 1
3190       || '\0' != name[size - sizeof (*req) - 1])
3191   {
3192     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3193                 "%p State get #%" PRIu64 ": "
3194                 "invalid name. size: %u < %zu?\n",
3195                 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
3196     GNUNET_break (0);
3197     GNUNET_SERVICE_client_drop (client);
3198     return;
3199   }
3200
3201   struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3202   opcls->client = c;
3203   opcls->op_id = req->op_id;
3204
3205   switch (ntohs (req->header.type))
3206   {
3207   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
3208       GNUNET_PSYC_channel_state_get (plc->channel, name,
3209                                      psyc_recv_state_var,
3210                                      psyc_recv_state_result, opcls);
3211       break;
3212
3213   case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
3214       GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
3215                                             psyc_recv_state_var,
3216                                             psyc_recv_state_result, opcls);
3217       break;
3218
3219   default:
3220       GNUNET_assert (0);
3221   }
3222
3223   GNUNET_SERVICE_client_continue (client);
3224 }
3225
3226
3227 #define check_client_state_get_prefix check_client_state_get
3228 #define handle_client_state_get_prefix handle_client_state_get
3229
3230
3231 static void
3232 namestore_recv_records_store_result (void *cls, int32_t result,
3233                                      const char *err_msg)
3234 {
3235   struct OperationClosure *opcls = cls;
3236   struct Client *c = opcls->client;
3237
3238   // FIXME: client might have been disconnected
3239   client_send_result (c->client, opcls->op_id, result, err_msg,
3240                       (NULL != err_msg) ? strlen (err_msg) : 0);
3241   GNUNET_free (opcls);
3242 }
3243
3244
3245 static int
3246 check_client_zone_add_place (void *cls,
3247                              const struct ZoneAddPlaceRequest *preq)
3248 {
3249   return GNUNET_OK;
3250 }
3251
3252
3253 /**
3254  * Handle request to add PLACE record to GNS zone.
3255  */
3256 static void
3257 handle_client_zone_add_place (void *cls,
3258                               const struct ZoneAddPlaceRequest *preq)
3259 {
3260   struct Client *c = cls;
3261   struct GNUNET_SERVICE_Client *client = c->client;
3262
3263   uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
3264   const char *p = (const char *) &preq[1];
3265   const char *name = NULL, *password = NULL;
3266   uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
3267                                                     &name, &password);
3268   remaining -= offset;
3269   p += offset;
3270   const struct GNUNET_PeerIdentity *
3271     relays = (const struct GNUNET_PeerIdentity *) p;
3272   uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
3273
3274   if (0 == offset || remaining != relay_size)
3275   {
3276     GNUNET_break (0);
3277     client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
3278     GNUNET_SERVICE_client_drop (client);
3279     return;
3280   }
3281
3282   struct GNUNET_GNSRECORD_Data rd = { };
3283   rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
3284   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
3285   rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
3286
3287   struct GNUNET_GNSRECORD_PlaceData *
3288     rec = GNUNET_malloc (sizeof (*rec) + relay_size);
3289   rec->place_pub_key = preq->place_pub_key;
3290   rec->origin = this_peer;
3291   rec->relay_count = preq->relay_count;
3292   GNUNET_memcpy (&rec[1], relays, relay_size);
3293
3294   rd.data = rec;
3295   rd.data_size = sizeof (*rec) + relay_size;
3296
3297   struct GNUNET_HashCode ego_pub_hash;
3298   GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash);
3299   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3300   if (NULL == ego)
3301   {
3302     client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
3303   }
3304   else
3305   {
3306     struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3307     opcls->client = c;
3308     opcls->op_id = preq->op_id;
3309     GNUNET_NAMESTORE_records_store (namestore, &ego->key,
3310                                     name, 1, &rd,
3311                                     namestore_recv_records_store_result, opcls);
3312     /** @todo refresh stored records later */
3313   }
3314   GNUNET_SERVICE_client_continue (client);
3315 }
3316
3317
3318 static int
3319 check_client_zone_add_nym (void *cls,
3320                            const struct ZoneAddNymRequest *nreq)
3321 {
3322   return GNUNET_OK;
3323 }
3324
3325
3326 /**
3327  * Handle request to add PLACE record to GNS zone.
3328  */
3329 static void
3330 handle_client_zone_add_nym (void *cls,
3331                             const struct ZoneAddNymRequest *nreq)
3332 {
3333   struct Client *c = cls;
3334   struct GNUNET_SERVICE_Client *client = c->client;
3335
3336   uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
3337   const char *name = NULL;
3338   uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
3339                                                     name_size, 1, &name);
3340   if (0 == offset || offset != name_size)
3341   {
3342     GNUNET_break (0);
3343     client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3344     GNUNET_SERVICE_client_continue (client);
3345     return;
3346   }
3347
3348   struct GNUNET_GNSRECORD_Data rd = { };
3349   rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
3350   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
3351   rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
3352   rd.data = &nreq->nym_pub_key;
3353   rd.data_size = sizeof (nreq->nym_pub_key);
3354
3355   struct GNUNET_HashCode ego_pub_hash;
3356   GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash);
3357   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3358   if (NULL == ego)
3359   {
3360     client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3361   }
3362   else
3363   {
3364     struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3365     opcls->client = c;
3366     opcls->op_id = nreq->op_id;
3367     GNUNET_NAMESTORE_records_store (namestore, &ego->key,
3368                                     name, 1, &rd,
3369                                     namestore_recv_records_store_result, opcls);
3370     /** @todo refresh stored records later */
3371   }
3372   GNUNET_SERVICE_client_continue (client);
3373 }
3374
3375
3376 const char *
3377 path_basename (const char *path)
3378 {
3379   const char *basename = strrchr (path, DIR_SEPARATOR);
3380   if (NULL != basename)
3381     basename++;
3382
3383   if (NULL == basename || '\0' == basename)
3384     return NULL;
3385
3386   return basename;
3387 }
3388
3389
3390 struct PlaceLoadClosure
3391 {
3392   const char *app_id;
3393   const char *ego_pub_str;
3394 };
3395
3396
3397 /** Load a place file */
3398 int
3399 file_place_load (void *cls, const char *place_filename)
3400 {
3401   struct PlaceLoadClosure *plcls = cls;
3402
3403   const char *place_pub_str = path_basename (place_filename);
3404   if (NULL == place_pub_str)
3405   {
3406     GNUNET_break (0);
3407     return GNUNET_OK;
3408   }
3409
3410   char *filename = NULL;
3411   GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
3412                    dir_social, DIR_SEPARATOR,
3413                    "places", DIR_SEPARATOR,
3414                    plcls->ego_pub_str, DIR_SEPARATOR,
3415                    place_pub_str);
3416
3417   uint64_t file_size = 0;
3418   if (GNUNET_OK !=
3419       GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
3420       || file_size < sizeof (struct PlaceEnterRequest))
3421   {
3422     GNUNET_free (filename);
3423     return GNUNET_OK;
3424   }
3425
3426   struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
3427   ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
3428   GNUNET_free (filename);
3429   if (read_size < 0 || read_size < sizeof (*ereq))
3430   {
3431     GNUNET_free (ereq);
3432     return GNUNET_OK;
3433   }
3434
3435   uint16_t ereq_size = ntohs (ereq->header.size);
3436   if (read_size != ereq_size)
3437   {
3438     GNUNET_free (ereq);
3439     return GNUNET_OK;
3440   }
3441
3442   switch (ntohs (ereq->header.type))
3443   {
3444   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
3445     if (ereq_size < sizeof (struct HostEnterRequest))
3446     {
3447       GNUNET_free (ereq);
3448       return GNUNET_OK;
3449     }
3450     struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
3451     host_enter (hreq, NULL);
3452     break;
3453
3454   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
3455     if (ereq_size < sizeof (struct GuestEnterRequest))
3456     {
3457       GNUNET_free (ereq);
3458       return GNUNET_OK;
3459     }
3460     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
3461     guest_enter (greq, NULL);
3462     break;
3463
3464   default:
3465     GNUNET_free (ereq);
3466     return GNUNET_OK;
3467   }
3468
3469   app_place_add (plcls->app_id, ereq);
3470   GNUNET_free (ereq);
3471   return GNUNET_OK;
3472 }
3473
3474
3475 /**
3476  * Read @e place_pub_str entries in @a dir_ego
3477  *
3478  * @param dir_ego
3479  *        Data directory of an application ego.
3480  *        $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_str/
3481  */
3482 int
3483 scan_app_ego_dir (void *cls, const char *dir_ego)
3484 {
3485   struct PlaceLoadClosure *plcls = cls;
3486   plcls->ego_pub_str = path_basename (dir_ego);
3487
3488   if (NULL != plcls->ego_pub_str)
3489     GNUNET_DISK_directory_scan (dir_ego, file_place_load, plcls);
3490
3491   return GNUNET_OK;
3492 }
3493
3494 /**
3495  * Read @e ego_pub_str entries in @a dir_app
3496  *
3497  * @param dir_app
3498  *        Data directory of an application.
3499  *        $GNUNET_DATA_HOME/social/apps/$app_id/
3500  */
3501 int
3502 scan_app_dir (void *cls, const char *dir_app)
3503 {
3504   if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
3505     return GNUNET_OK;
3506
3507   struct PlaceLoadClosure plcls;
3508   plcls.app_id = path_basename (dir_app);
3509
3510   if (NULL != plcls.app_id)
3511     GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
3512
3513   return GNUNET_OK;
3514 }
3515
3516
3517 static void
3518 identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
3519                    void **ctx, const char *name)
3520 {
3521   if (NULL == id_ego) // end of initial list of egos
3522     return;
3523
3524   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
3525   GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
3526
3527   struct GNUNET_HashCode ego_pub_hash;
3528   GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
3529
3530   struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3531   if (NULL != ego)
3532   {
3533     GNUNET_free (ego->name);
3534     if (NULL == name) // deleted
3535     {
3536       GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
3537       GNUNET_free (ego);
3538       ego = NULL;
3539     }
3540   }
3541   else
3542   {
3543     ego = GNUNET_malloc (sizeof (*ego));
3544   }
3545   if (NULL != ego)
3546   {
3547     ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
3548     size_t name_size = strlen (name) + 1;
3549     ego->name = GNUNET_malloc (name_size);
3550     GNUNET_memcpy (ego->name, name, name_size);
3551
3552     GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
3553                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
3554   }
3555
3556   // FIXME: notify clients about changed ego
3557 }
3558
3559
3560 /**
3561  * Initialize the PSYC service.
3562  *
3563  * @param cls Closure.
3564  * @param server The initialized server.
3565  * @param c Configuration to use.
3566  */
3567 static void
3568 run (void *cls,
3569      const struct GNUNET_CONFIGURATION_Handle *c,
3570      struct GNUNET_SERVICE_Handle *svc)
3571 {
3572   cfg = c;
3573   service = svc;
3574   GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
3575
3576   hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3577   guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3578   place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3579
3580   egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3581   apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3582   places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3583   apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3584   places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3585
3586   id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
3587   gns = GNUNET_GNS_connect (cfg);
3588   namestore = GNUNET_NAMESTORE_connect (cfg);
3589   stats = GNUNET_STATISTICS_create ("social", cfg);
3590
3591   if (GNUNET_OK !=
3592       GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME",
3593                                                &dir_social))
3594   {
3595     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3596                                "social", "DATA_HOME");
3597     GNUNET_break (0);
3598     return;
3599   }
3600   GNUNET_asprintf (&dir_places, "%s%c%s",
3601                    dir_social, DIR_SEPARATOR, "places");
3602   GNUNET_asprintf (&dir_apps, "%s%c%s",
3603                    dir_social, DIR_SEPARATOR, "apps");
3604
3605   GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
3606
3607   GNUNET_SCHEDULER_add_shutdown (shutdown_task, NULL);
3608 }
3609
3610
3611 /**
3612  * Define "main" method using service macro.
3613  */
3614 GNUNET_SERVICE_MAIN
3615 ("social",
3616  GNUNET_SERVICE_OPTION_NONE,
3617  run,
3618  client_notify_connect,
3619  client_notify_disconnect,
3620  NULL,
3621  GNUNET_MQ_hd_var_size (client_host_enter,
3622                         GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER,
3623                         struct HostEnterRequest,
3624                         NULL),
3625  GNUNET_MQ_hd_var_size (client_guest_enter,
3626                         GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER,
3627                         struct GuestEnterRequest,
3628                         NULL),
3629  GNUNET_MQ_hd_var_size (client_guest_enter_by_name,
3630                         GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME,
3631                         struct GuestEnterByNameRequest,
3632                         NULL),
3633  GNUNET_MQ_hd_var_size (client_join_decision,
3634                         GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
3635                         struct GNUNET_PSYC_JoinDecisionMessage,
3636                         NULL),
3637  GNUNET_MQ_hd_var_size (client_psyc_message,
3638                         GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
3639                         struct GNUNET_MessageHeader,
3640                         NULL),
3641  GNUNET_MQ_hd_var_size (client_history_replay,
3642                         GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY,
3643                         struct GNUNET_PSYC_HistoryRequestMessage,
3644                         NULL),
3645  GNUNET_MQ_hd_var_size (client_state_get,
3646                         GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
3647                         struct GNUNET_PSYC_StateRequestMessage,
3648                         NULL),
3649  GNUNET_MQ_hd_var_size (client_state_get_prefix,
3650                         GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
3651                         struct GNUNET_PSYC_StateRequestMessage,
3652                         NULL),
3653  GNUNET_MQ_hd_var_size (client_zone_add_place,
3654                         GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE,
3655                         struct ZoneAddPlaceRequest,
3656                         NULL),
3657  GNUNET_MQ_hd_var_size (client_zone_add_nym,
3658                         GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM,
3659                         struct ZoneAddNymRequest,
3660                         NULL),
3661  GNUNET_MQ_hd_var_size (client_app_connect,
3662                         GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT,
3663                         struct AppConnectRequest,
3664                         NULL),
3665  GNUNET_MQ_hd_fixed_size (client_app_detach,
3666                           GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH,
3667                           struct AppDetachRequest,
3668                           NULL),
3669  GNUNET_MQ_hd_fixed_size (client_place_leave,
3670                           GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE,
3671                           struct GNUNET_MessageHeader,
3672                           NULL),
3673  GNUNET_MQ_hd_var_size (client_msg_proc_set,
3674                         GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET,
3675                         struct MsgProcRequest,
3676                         NULL),
3677  GNUNET_MQ_hd_fixed_size (client_msg_proc_clear,
3678                           GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR,
3679                           struct GNUNET_MessageHeader,
3680                           NULL));
3681
3682 /* end of gnunet-service-social.c */