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