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