Mockup for the mesh-api
[oweals/gnunet.git] / src / mesh / mesh_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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 mesh/mesh_api.c
23  * @brief mesh service; API for the Mesh. This is used to talk to arbitrary peers
24  *        as of 2011-01Jan-06 this is a mockup.
25  * @author Philipp Tölke
26  */
27 #include <platform.h>
28 #include <gnunet_constants.h>
29 #include <gnunet_mesh_service.h>
30 #include <gnunet_core_service.h>
31 #include <gnunet_container_lib.h>
32
33 struct tunnel_id
34 {
35   uint32_t id;
36   struct GNUNET_PeerIdentity initiator;
37   struct GNUNET_PeerIdentity target;
38 };
39
40 static uint32_t current_id = 0;
41
42 struct tunnel_message
43 {
44   struct GNUNET_MessageHeader hdr;
45   struct tunnel_id id;
46   /* followed by another GNUNET_MessageHeader */
47 };
48
49 struct GNUNET_MESH_Tunnel
50 {
51   /* The other peer this tunnel leads to; just unicast for the moment! */
52   struct GNUNET_PeerIdentity peer;
53
54   struct tunnel_id id;
55
56   void* notify_cls;
57   GNUNET_CONNECTION_TransmitReadyNotify notify;
58
59   /* The handlers and cls for outbound tunnels. Are NULL for inbound tunnels. */
60   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
61   GNUNET_MESH_TunnelConnectHandler connect_handler;
62   void *handler_cls;
63
64   struct GNUNET_MESH_Handle* handle;
65
66   /* The context of the receive-function. */
67   void *ctx;
68 };
69
70 struct tunnel_list_element
71 {
72   struct GNUNET_MESH_Tunnel tunnel;
73   struct tunnel_list_element *next, *prev;
74 };
75
76 struct tunnel_list
77 {
78   struct tunnel_list_element *head, *tail;
79 };
80
81 struct peer_list_element
82 {
83   struct GNUNET_PeerIdentity peer;
84   struct GNUNET_TRANSPORT_ATS_Information atsi;
85   struct peer_list_element *next, *prev;
86 };
87
88 struct peer_list
89 {
90   struct peer_list_element *head, *tail;
91 };
92
93 struct GNUNET_MESH_Handle
94 {
95   struct GNUNET_CORE_Handle *core;
96   struct GNUNET_MESH_MessageHandler *handlers;
97   struct GNUNET_PeerIdentity myself;
98   unsigned int connected_to_core;
99   struct peer_list connected_peers;
100   struct tunnel_list established_tunnels;
101   struct tunnel_list pending_tunnels;
102   void *cls;
103   GNUNET_MESH_TunnelEndHandler *cleaner;
104 };
105
106 static void
107 core_startup (void *cls,
108               struct GNUNET_CORE_Handle *core,
109               const struct GNUNET_PeerIdentity *my_identity,
110               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
111 {
112   struct GNUNET_MESH_Handle *handle = cls;
113   memcpy (&handle->myself, my_identity, sizeof (struct GNUNET_PeerIdentity));
114   handle->connected_to_core = GNUNET_YES;
115 }
116
117 /**
118  * Core calls this if we are connected to a new peer.
119  *
120  * If core tells us that we are connected to ourself, we ignore it. Otherwise, the
121  * peer is added to the connected_peers-list.
122  *
123  */
124 static void
125 core_connect (void *cls,
126               const struct GNUNET_PeerIdentity *peer,
127               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
128 {
129   struct GNUNET_MESH_Handle *handle = cls;
130   /* Check for connect-to-self-message, which we ignore */
131   if (0 ==
132       memcmp (peer, &handle->myself, sizeof (struct GNUNET_PeerIdentity)))
133     return;
134
135
136   /* put the new peer into the list of connected peers */
137   struct peer_list_element *element =
138     GNUNET_malloc (sizeof (struct peer_list_element));
139   memcpy (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity));
140   memcpy (&element->atsi, atsi,
141           sizeof (struct GNUNET_TRANSPORT_ATS_Information));
142
143   GNUNET_CONTAINER_DLL_insert_after (handle->connected_peers.head,
144                                      handle->connected_peers.tail,
145                                      handle->connected_peers.tail, element);
146
147   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
148   while (tunnel != NULL)
149     {
150       if (0 ==
151           memcmp (&tunnel->tunnel.peer, peer,
152                   sizeof (struct GNUNET_PeerIdentity)))
153         {
154           struct tunnel_list_element *next = tunnel->next;
155           GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
156                                        handle->pending_tunnels.tail, tunnel);
157           GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
158                                              handle->established_tunnels.tail,
159                                              handle->established_tunnels.tail,
160                                              tunnel);
161           tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
162                                           peer, atsi);
163           tunnel = next;
164         }
165       else
166         tunnel = tunnel->next;
167     }
168 }
169
170 /**
171  * Core calls this if we disconnect a peer
172  *
173  * Remove this peer from the list of connected peers
174  * Close all tunnels this peer belongs to
175  */
176 static void
177 core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
178 {
179   struct GNUNET_MESH_Handle *handle = cls;
180
181   struct peer_list_element *element = handle->connected_peers.head;
182   while (element != NULL)
183     {
184       if (0 ==
185           memcmp (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity)))
186         break;
187       element = element->next;
188     }
189   if (element != NULL)
190     {
191       GNUNET_CONTAINER_DLL_remove (handle->connected_peers.head,
192                                    handle->connected_peers.tail, element);
193       GNUNET_free (element);
194     }
195
196   struct tunnel_list_element *telement = handle->established_tunnels.head;
197   while (telement != NULL)
198     {
199       if (0 ==
200           memcmp (&telement->tunnel.peer, peer,
201                   sizeof (struct GNUNET_PeerIdentity)))
202         {
203           /* disconnect tunnels */
204           /* outbound tunnels */
205           if (telement->tunnel.connect_handler != NULL)
206             telement->tunnel.disconnect_handler (telement->tunnel.handler_cls,
207                                                  peer);
208           /* inbound tunnels */
209           else
210             handle->cleaner (handle->cls, &telement->tunnel,
211                              &telement->tunnel.ctx);
212
213           struct tunnel_list_element *next = telement->next;
214           GNUNET_CONTAINER_DLL_remove (handle->established_tunnels.head,
215                                        handle->established_tunnels.tail,
216                                        telement);
217           GNUNET_free (telement);
218           telement = next;
219         }
220       else
221         {
222           telement = telement->next;
223         }
224     }
225 }
226
227 /**
228  * Receive a message from core.
229  */
230 static int
231 core_receive (void *cls,
232               const struct GNUNET_PeerIdentity *other,
233               const struct GNUNET_MessageHeader *message,
234               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
235 {
236   struct GNUNET_MESH_Handle *handle = cls;
237   struct tunnel_message *tmessage = (struct tunnel_message *) message;
238   struct GNUNET_MessageHeader *rmessage =
239     (struct GNUNET_MessageHeader *) (tmessage + 1);
240
241   struct GNUNET_MESH_MessageHandler *handler;
242
243   for (handler = handle->handlers; handler != NULL; handler++)
244     {
245       if (ntohs (rmessage->type) == handler->type
246           && (handler->expected_size == 0
247               || handler->expected_size == ntohs (rmessage->size)))
248         {
249           break;
250         }
251     }
252
253   /* handler->callback handles this message */
254
255   /* If no handler was found, drop the message but keep the channel open */
256   if (handler == NULL)
257     return GNUNET_OK;
258
259   struct tunnel_list_element *tunnel = handle->established_tunnels.head;
260
261   while (tunnel != NULL)
262     {
263       if (tunnel->tunnel.id.id == tmessage->id.id &&
264           (0 ==
265            memcmp (&tmessage->id.initiator, &tunnel->tunnel.id.initiator,
266                    sizeof (struct GNUNET_PeerIdentity)))
267           && (0 ==
268               memcmp (&tmessage->id.target, &tunnel->tunnel.id.target,
269                       sizeof (struct GNUNET_PeerIdentity))))
270         break;
271       tunnel = tunnel->next;
272     }
273
274   /* if no tunnel was found: create a new inbound tunnel */
275   if (tunnel == NULL)
276     {
277       tunnel = GNUNET_malloc (sizeof (struct tunnel_list_element));
278       tunnel->tunnel.connect_handler = NULL;
279       tunnel->tunnel.disconnect_handler = NULL;
280       tunnel->tunnel.handler_cls = NULL;
281       tunnel->tunnel.ctx = NULL;
282       tunnel->tunnel.handle = handle;
283       memcpy (&tunnel->tunnel.peer, other,
284               sizeof (struct GNUNET_PeerIdentity));
285       memcpy (&tunnel->tunnel.id, &tmessage->id, sizeof (struct tunnel_id));
286
287       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
288                                          handle->established_tunnels.tail,
289                                          handle->established_tunnels.tail,
290                                          tunnel);
291     }
292
293   return handler->callback (handle->cls, &tunnel->tunnel,
294                             &tunnel->tunnel.ctx, rmessage, atsi);
295 }
296
297
298 struct GNUNET_MESH_Tunnel *
299 GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle,
300                                       struct GNUNET_TIME_Relative timeout,
301                                       unsigned int num_peers,
302                                       const struct GNUNET_PeerIdentity *peers,
303                                       GNUNET_MESH_TunnelConnectHandler
304                                       connect_handler,
305                                       GNUNET_MESH_TunnelDisconnectHandler
306                                       disconnect_handler, void *handler_cls)
307 {
308   if (num_peers != 1)
309     return NULL;
310
311   struct tunnel_list_element *tunnel =
312     GNUNET_malloc (sizeof (struct tunnel_list_element));
313
314   tunnel->tunnel.connect_handler = connect_handler;
315   tunnel->tunnel.disconnect_handler = disconnect_handler;
316   tunnel->tunnel.handler_cls = handler_cls;
317   tunnel->tunnel.ctx = NULL;
318   tunnel->tunnel.handle = handle;
319   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
320           sizeof (struct GNUNET_PeerIdentity));
321   memcpy (&tunnel->tunnel.id.target, peers,
322           sizeof (struct GNUNET_PeerIdentity));
323   tunnel->tunnel.id.id = current_id++;
324
325   struct peer_list_element *element = handle->connected_peers.head;
326   while (element != NULL)
327     {
328       if (0 ==
329           memcmp (&element->peer, peers, sizeof (struct GNUNET_PeerIdentity)))
330         break;
331       element = element->next;
332     }
333
334   if (element != NULL)
335     {
336       /* we are connected to this peer */
337       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
338                                          handle->established_tunnels.tail,
339                                          handle->established_tunnels.tail,
340                                          tunnel);
341       connect_handler (handler_cls, &element->peer, &element->atsi);
342     }
343   else if (0 ==
344            memcmp (peers, &handle->myself,
345                    sizeof (struct GNUNET_PeerIdentity)))
346     {
347       /* we are the peer */
348       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
349                                          handle->established_tunnels.tail,
350                                          handle->established_tunnels.tail,
351                                          tunnel);
352       connect_handler (handler_cls, &handle->myself, NULL);
353     }
354   else
355     {
356       /* we are not connected to this peer */
357       GNUNET_CONTAINER_DLL_insert_after (handle->pending_tunnels.head,
358                                          handle->pending_tunnels.tail,
359                                          handle->pending_tunnels.tail,
360                                          tunnel);
361     }
362
363   return &tunnel->tunnel;
364 }
365
366 static size_t
367 core_notify(void* cls, size_t size, void* buf)
368 {
369   struct GNUNET_MESH_Tunnel *tunnel = cls;
370   struct tunnel_message* message = buf;
371   void* cbuf = (void*)(message + 1);
372
373   size_t sent = tunnel->notify(tunnel->notify_cls, size - sizeof(struct tunnel_message), cbuf);
374
375   tunnel->notify = NULL;
376   tunnel->notify_cls = NULL;
377
378   sent += sizeof(struct tunnel_message);
379
380   message->hdr.type = htons(GNUNET_MESSAGE_TYPE_MESH);
381   message->hdr.size = htons(sent);
382   memcpy(&message->id, &tunnel->id, sizeof(struct tunnel_id));
383   return sent;
384 }
385
386 struct GNUNET_MESH_TransmitHandle *
387 GNUNET_MESH_notify_transmit_ready (struct
388                                    GNUNET_MESH_Tunnel
389                                    *tunnel,
390                                    int cork,
391                                    uint32_t priority,
392                                    struct
393                                    GNUNET_TIME_Relative
394                                    maxdelay,
395                                    size_t
396                                    notify_size,
397                                    GNUNET_CONNECTION_TransmitReadyNotify
398                                    notify, void *notify_cls)
399 {
400   tunnel->notify_cls = notify_cls;
401   tunnel->notify = notify;
402   GNUNET_CORE_notify_transmit_ready(tunnel->handle->core,
403                                     priority,
404                                     maxdelay,
405                                     &tunnel->peer,
406                                     notify_size + sizeof(struct tunnel_message),
407                                     core_notify,
408                                     (void*)tunnel);
409
410   /* aborting is not implemented yet */
411   return (struct GNUNET_MESH_TransmitHandle*)1;
412 }
413
414
415 struct GNUNET_MESH_Handle *
416 GNUNET_MESH_connect (const struct
417                      GNUNET_CONFIGURATION_Handle
418                      *cfg, void *cls,
419                      GNUNET_MESH_TunnelEndHandler
420                      cleaner,
421                      const struct GNUNET_MESH_MessageHandler *handlers)
422 {
423   struct GNUNET_MESH_Handle *ret =
424     GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
425
426   ret->connected_to_core = GNUNET_NO;
427   ret->connected_peers.head = NULL;
428   ret->connected_peers.tail = NULL;
429   ret->cleaner = cleaner;
430   ret->cls = cls;
431
432   const struct GNUNET_MESH_MessageHandler *it;
433   unsigned int len = 1;
434   for (it = handlers; it->callback != NULL; it++)
435     {
436       len++;
437     }
438
439   ret->handlers =
440     GNUNET_malloc (len * sizeof (struct GNUNET_MESH_MessageHandler));
441   memcpy (ret->handlers, handlers,
442           len * sizeof (struct GNUNET_MESH_MessageHandler));
443
444   const static struct GNUNET_CORE_MessageHandler core_handlers[] = {
445     {core_receive, GNUNET_MESSAGE_TYPE_MESH, 0},
446     {NULL, 0, 0}
447   };
448
449   ret->core = GNUNET_CORE_connect (cfg,
450                                    42,
451                                    ret,
452                                    core_startup,
453                                    core_connect,
454                                    core_disconnect,
455                                    NULL,
456                                    NULL,
457                                    GNUNET_NO, NULL, GNUNET_NO, core_handlers);
458   return ret;
459 }
460
461 void
462 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
463 {
464   GNUNET_free (handle->handlers);
465   GNUNET_CORE_disconnect (handle->core);
466
467   struct peer_list_element *element = handle->connected_peers.head;
468   while (element != NULL)
469     {
470       struct peer_list_element *next = element->next;
471       GNUNET_free (element);
472       element = next;
473     }
474
475   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
476   while (tunnel != NULL)
477     {
478       struct tunnel_list_element *next = tunnel->next;
479       GNUNET_free (tunnel);
480       tunnel = next;
481     }
482   tunnel = handle->established_tunnels.head;;
483   while (tunnel != NULL)
484     {
485       struct tunnel_list_element *next = tunnel->next;
486       GNUNET_free (tunnel);
487       tunnel = next;
488     }
489
490   GNUNET_free (handle);
491 }
492
493 /* end of core_api.c */