PSYC util lib: receiving/transmitting/logging PSYC messages
[oweals/gnunet.git] / src / social / gnunet-service-social.c
1 /*
2  * This file is part of GNUnet
3  * (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file psyc/gnunet-service-social.c
23  * @brief Social service
24  * @author Gabor X Toth
25  */
26
27 #include <inttypes.h>
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_psyc_service.h"
35 #include "gnunet_social_service.h"
36 #include "social.h"
37
38
39 /**
40  * Handle to our current configuration.
41  */
42 static const struct GNUNET_CONFIGURATION_Handle *cfg;
43
44 /**
45  * Handle to the statistics service.
46  */
47 static struct GNUNET_STATISTICS_Handle *stats;
48
49 /**
50  * Notification context, simplifies client broadcasts.
51  */
52 static struct GNUNET_SERVER_NotificationContext *nc;
53
54 /**
55  * All connected hosts.
56  * Place's pub_key_hash -> struct Host
57  */
58 static struct GNUNET_CONTAINER_MultiHashMap *hosts;
59
60 /**
61  * All connected guests.
62  * Place's pub_key_hash -> struct Guest
63  */
64 static struct GNUNET_CONTAINER_MultiHashMap *guests;
65
66 /**
67  * Connected guests per place.
68  * Place's pub_key_hash -> Guest's pub_key -> struct Guest
69  */
70 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
71
72
73 /**
74  * Message in the transmission queue.
75  */
76 struct TransmitMessage
77 {
78   struct TransmitMessage *prev;
79   struct TransmitMessage *next;
80
81   struct GNUNET_SERVER_Client *client;
82
83   /**
84    * ID assigned to the message.
85    */
86   uint64_t id;
87
88   /**
89    * Size of @a buf
90    */
91   uint16_t size;
92
93   /**
94    * @see enum MessageState
95    */
96   uint8_t state;
97
98   /* Followed by message */
99 };
100
101
102 /**
103  * List of connected clients.
104  */
105 struct ClientList
106 {
107   struct ClientList *prev;
108   struct ClientList *next;
109   struct GNUNET_SERVER_Client *client;
110 };
111
112
113 /**
114  * Common part of the client context for both a host and guest.
115  */
116 struct Place
117 {
118   struct ClientList *clients_head;
119   struct ClientList *clients_tail;
120
121   struct TransmitMessage *tmit_head;
122   struct TransmitMessage *tmit_tail;
123
124   /**
125    * Public key of the channel.
126    */
127   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
128
129   /**
130    * Hash of @a pub_key.
131    */
132   struct GNUNET_HashCode pub_key_hash;
133
134   /**
135    * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
136    */
137   uint8_t is_host;
138 };
139
140
141 /**
142  * Client context for a host.
143  */
144 struct Host
145 {
146   /**
147    * Place struct common for Host and Guest
148    */
149   struct Place pl;
150
151   /**
152    * Private key of the channel.
153    */
154   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
155
156   /**
157    * Handle for the multicast origin.
158    */
159   struct GNUNET_PSYC_Master *master;
160
161   /**
162    * Transmit handle for multicast.
163    */
164   struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
165
166   /**
167    * Incoming join requests.
168    * guest_key -> struct GNUNET_PSYC_JoinHandle *
169    */
170   struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
171
172   /**
173    * @see enum GNUNET_PSYC_Policy
174    */
175   enum GNUNET_PSYC_Policy policy;
176 };
177
178
179 /**
180  * Client context for a guest.
181  */
182 struct Guest
183 {
184   /**
185    * Place struct common for Host and Guest.
186    */
187   struct Place pl;
188
189   /**
190    * Private key of the slave.
191    */
192   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
193
194   /**
195    * Public key of the slave.
196    */
197   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
198
199   /**
200    * Hash of @a pub_key.
201    */
202   struct GNUNET_HashCode pub_key_hash;
203
204   /**
205    * Handle for the PSYC slave.
206    */
207   struct GNUNET_PSYC_Slave *slave;
208
209   /**
210    * Transmit handle for multicast.
211    */
212   struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
213
214   /**
215    * Peer identity of the origin.
216    */
217   struct GNUNET_PeerIdentity origin;
218
219   /**
220    * Number of items in @a relays.
221    */
222   uint32_t relay_count;
223
224   /**
225    * Relays that multicast can use to connect.
226    */
227   struct GNUNET_PeerIdentity *relays;
228
229   /**
230    * Join request to be transmitted to the master on join.
231    */
232   struct GNUNET_MessageHeader *join_req;
233 };
234
235
236 static inline void
237 transmit_message (struct Place *pl);
238
239
240 /**
241  * Task run during shutdown.
242  *
243  * @param cls unused
244  * @param tc unused
245  */
246 static void
247 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
248 {
249   if (NULL != nc)
250   {
251     GNUNET_SERVER_notification_context_destroy (nc);
252     nc = NULL;
253   }
254   if (NULL != stats)
255   {
256     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
257     stats = NULL;
258   }
259 }
260
261
262 /**
263  * Clean up host data structures after a client disconnected.
264  */
265 static void
266 cleanup_host (struct Host *hst)
267 {
268   struct Place *pl = &hst->pl;
269
270   if (NULL != hst->master)
271     GNUNET_PSYC_master_stop (hst->master);
272   GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
273   GNUNET_CONTAINER_multihashmap_remove (hosts, &pl->pub_key_hash, pl);
274 }
275
276
277 /**
278  * Clean up guest data structures after a client disconnected.
279  */
280 static void
281 cleanup_guest (struct Guest *gst)
282 {
283   struct Place *pl = &gst->pl;
284   struct GNUNET_CONTAINER_MultiHashMap *
285     pl_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
286                                                 &pl->pub_key_hash);
287   GNUNET_assert (NULL != pl_gst);
288   GNUNET_CONTAINER_multihashmap_remove (pl_gst, &gst->pub_key_hash, gst);
289
290   if (0 == GNUNET_CONTAINER_multihashmap_size (pl_gst))
291   {
292     GNUNET_CONTAINER_multihashmap_remove (place_guests, &pl->pub_key_hash,
293                                           pl_gst);
294     GNUNET_CONTAINER_multihashmap_destroy (pl_gst);
295   }
296   GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, gst);
297
298   if (NULL != gst->join_req)
299     GNUNET_free (gst->join_req);
300   if (NULL != gst->relays)
301     GNUNET_free (gst->relays);
302   if (NULL != gst->slave)
303     GNUNET_PSYC_slave_part (gst->slave);
304   GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, pl);
305 }
306
307
308 /**
309  * Clean up place data structures after a client disconnected.
310  */
311 static void
312 cleanup_place (struct Place *pl)
313 {
314   (GNUNET_YES == pl->is_host)
315     ? cleanup_host ((struct Host *) pl)
316     : cleanup_guest ((struct Guest *) pl);
317   GNUNET_free (pl);
318 }
319
320
321 /**
322  * Called whenever a client is disconnected.
323  * Frees our resources associated with that client.
324  *
325  * @param cls Closure.
326  * @param client Identification of the client.
327  */
328 static void
329 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
330 {
331   if (NULL == client)
332     return;
333
334   struct Place *
335     pl = GNUNET_SERVER_client_get_user_context (client, struct Place);
336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337               "%p Client (%s) disconnected from place %s\n",
338               pl, (GNUNET_YES == pl->is_host) ? "host" : "guest",
339               GNUNET_h2s (&pl->pub_key_hash));
340
341   if (NULL == pl)
342   {
343     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
344                 "%p User context is NULL in client_disconnect()\n", pl);
345     GNUNET_break (0);
346     return;
347   }
348
349   struct ClientList *cl = pl->clients_head;
350   while (NULL != cl)
351   {
352     if (cl->client == client)
353     {
354       GNUNET_CONTAINER_DLL_remove (pl->clients_head, pl->clients_tail, cl);
355       GNUNET_free (cl);
356       break;
357     }
358     cl = cl->next;
359   }
360
361   if (NULL == pl->clients_head)
362   { /* Last client disconnected. */
363     if (NULL != pl->tmit_head)
364     { /* Send pending messages to PSYC before cleanup. */
365       //FIXME: transmit_message (pl);
366     }
367     else
368     {
369       cleanup_place (pl);
370     }
371   }
372 }
373
374
375 static void
376 client_home_enter (void *cls, struct GNUNET_SERVER_Client *client,
377                    const struct GNUNET_MessageHeader *msg)
378 {
379
380 }
381
382
383 static void
384 client_place_enter (void *cls, struct GNUNET_SERVER_Client *client,
385                     const struct GNUNET_MessageHeader *msg)
386 {
387
388 }
389
390
391 static void
392 client_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
393                       const struct GNUNET_MessageHeader *msg)
394 {
395
396 }
397
398
399 static void
400 client_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
401                      const struct GNUNET_MessageHeader *msg)
402 {
403
404 }
405
406
407 /**
408  * Initialize the PSYC service.
409  *
410  * @param cls Closure.
411  * @param server The initialized server.
412  * @param c Configuration to use.
413  */
414 static void
415 run (void *cls, struct GNUNET_SERVER_Handle *server,
416      const struct GNUNET_CONFIGURATION_Handle *c)
417 {
418   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
419     { &client_home_enter, NULL,
420       GNUNET_MESSAGE_TYPE_SOCIAL_HOME_ENTER, 0 },
421
422     { &client_place_enter, NULL,
423       GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_ENTER, 0 },
424
425     { &client_join_decision, NULL,
426       GNUNET_MESSAGE_TYPE_SOCIAL_JOIN_DECISION, 0 },
427
428     { &client_psyc_message, NULL,
429       GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 }
430   };
431
432   cfg = c;
433   stats = GNUNET_STATISTICS_create ("social", cfg);
434   hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
435   guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
436   place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
437   nc = GNUNET_SERVER_notification_context_create (server, 1);
438   GNUNET_SERVER_add_handlers (server, handlers);
439   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
440   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
441                                 &shutdown_task, NULL);
442 }
443
444
445 /**
446  * The main function for the service.
447  *
448  * @param argc number of arguments from the command line
449  * @param argv command line arguments
450  * @return 0 ok, 1 on error
451  */
452 int
453 main (int argc, char *const *argv)
454 {
455   return (GNUNET_OK ==
456           GNUNET_SERVICE_run (argc, argv, "social",
457                               GNUNET_SERVICE_OPTION_NONE,
458                               &run, NULL)) ? 0 : 1;
459 }
460
461 /* end of gnunet-service-social.c */