- add underlay api implementation
[oweals/gnunet.git] / src / mesh / mesh_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4      GNUnet is free software; you can redistribute it and/or modify
5      it under the terms of the GNU General Public License as published
6      by the Free Software Foundation; either version 3, or (at your
7      option) any later version.
8      GNUnet is distributed in the hope that it will be useful, but
9      WITHOUT ANY WARRANTY; without even the implied warranty of
10      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11      General Public License for more details.
12      You should have received a copy of the GNU General Public License
13      along with GNUnet; see the file COPYING.  If not, write to the
14      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15      Boston, MA 02111-1307, USA.
16 */
17
18 /**
19  * @file mesh/mesh_api.c
20  * @brief mesh api: client implementation of new mesh service
21  * @author Bartlomiej Polot
22  */
23
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_mesh_service.h"
27 #include "mesh.h"
28 #include "mesh_protocol.h"
29
30 #define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
31
32 /******************************************************************************/
33 /************************      DATA STRUCTURES     ****************************/
34 /******************************************************************************/
35
36 /**
37  * Transmission queue to the service
38  */
39 struct GNUNET_MESH_TransmitHandle
40 {
41
42     /**
43      * Double Linked list
44      */
45   struct GNUNET_MESH_TransmitHandle *next;
46
47     /**
48      * Double Linked list
49      */
50   struct GNUNET_MESH_TransmitHandle *prev;
51
52     /**
53      * Channel this message is sent on / for (may be NULL for control messages).
54      */
55   struct GNUNET_MESH_Channel *channel;
56
57     /**
58      * Callback to obtain the message to transmit, or NULL if we
59      * got the message in 'data'.  Notice that messages built
60      * by 'notify' need to be encapsulated with information about
61      * the 'target'.
62      */
63   GNUNET_CONNECTION_TransmitReadyNotify notify;
64
65     /**
66      * Closure for 'notify'
67      */
68   void *notify_cls;
69
70     /**
71      * How long is this message valid.  Once the timeout has been
72      * reached, the message must no longer be sent.  If this
73      * is a message with a 'notify' callback set, the 'notify'
74      * function should be called with 'buf' NULL and size 0.
75      */
76   struct GNUNET_TIME_Absolute timeout;
77
78     /**
79      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
80      */
81   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
82
83     /**
84      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
85      */
86   size_t size;
87 };
88
89
90 /**
91  * Opaque handle to the service.
92  */
93 struct GNUNET_MESH_Handle
94 {
95
96     /**
97      * Handle to the server connection, to send messages later
98      */
99   struct GNUNET_CLIENT_Connection *client;
100
101     /**
102      * Set of handlers used for processing incoming messages in the channels
103      */
104   const struct GNUNET_MESH_MessageHandler *message_handlers;
105
106   /**
107    * Number of handlers in the handlers array.
108    */
109   unsigned int n_handlers;
110
111   /**
112    * Ports open.
113    */
114   const uint32_t *ports;
115
116   /**
117    * Number of ports.
118    */
119   unsigned int n_ports;
120
121     /**
122      * Double linked list of the channels this client is connected to, head.
123      */
124   struct GNUNET_MESH_Channel *channels_head;
125
126     /**
127      * Double linked list of the channels this client is connected to, tail.
128      */
129   struct GNUNET_MESH_Channel *channels_tail;
130
131     /**
132      * Callback for inbound channel creation
133      */
134   GNUNET_MESH_InboundChannelNotificationHandler *new_channel;
135
136     /**
137      * Callback for inbound channel disconnection
138      */
139   GNUNET_MESH_ChannelEndHandler *cleaner;
140
141     /**
142      * Handle to cancel pending transmissions in case of disconnection
143      */
144   struct GNUNET_CLIENT_TransmitHandle *th;
145
146     /**
147      * Closure for all the handlers given by the client
148      */
149   void *cls;
150
151     /**
152      * Messages to send to the service, head.
153      */
154   struct GNUNET_MESH_TransmitHandle *th_head;
155
156     /**
157      * Messages to send to the service, tail.
158      */
159   struct GNUNET_MESH_TransmitHandle *th_tail;
160
161     /**
162      * chid of the next channel to create (to avoid reusing IDs often)
163      */
164   MESH_ChannelNumber next_chid;
165
166     /**
167      * Have we started the task to receive messages from the service
168      * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
169      */
170   int in_receive;
171
172   /**
173    * Configuration given by the client, in case of reconnection
174    */
175   const struct GNUNET_CONFIGURATION_Handle *cfg;
176
177   /**
178    * Time to the next reconnect in case one reconnect fails
179    */
180   struct GNUNET_TIME_Relative reconnect_time;
181
182   /**
183    * Task for trying to reconnect.
184    */
185   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
186
187   /**
188    * Monitor callback
189    */
190   GNUNET_MESH_ChannelsCB channels_cb;
191
192   /**
193    * Monitor callback closure.
194    */
195   void *channels_cls;
196
197   /**
198    * Channel callback.
199    */
200   GNUNET_MESH_ChannelCB channel_cb;
201
202   /**
203    * Channel callback closure.
204    */
205   void *channel_cls;
206 };
207
208
209 /**
210  * Description of a peer
211  */
212 struct GNUNET_MESH_Peer
213 {
214     /**
215      * ID of the peer in short form
216      */
217   GNUNET_PEER_Id id;
218
219   /**
220    * Channel this peer belongs to
221    */
222   struct GNUNET_MESH_Channel *t;
223 };
224
225
226 /**
227  * Opaque handle to a channel.
228  */
229 struct GNUNET_MESH_Channel
230 {
231
232     /**
233      * DLL next
234      */
235   struct GNUNET_MESH_Channel *next;
236
237     /**
238      * DLL prev
239      */
240   struct GNUNET_MESH_Channel *prev;
241
242     /**
243      * Handle to the mesh this channel belongs to
244      */
245   struct GNUNET_MESH_Handle *mesh;
246
247     /**
248      * Local ID of the channel
249      */
250   MESH_ChannelNumber chid;
251
252     /**
253      * Port number.
254      */
255   uint32_t port;
256
257     /**
258      * Other end of the channel.
259      */
260   GNUNET_PEER_Id peer;
261
262   /**
263    * Any data the caller wants to put in here
264    */
265   void *ctx;
266
267     /**
268      * Size of packet queued in this channel
269      */
270   unsigned int packet_size;
271
272     /**
273      * Channel options: reliability, etc.
274      */
275   enum GNUNET_MESH_ChannelOption options;
276
277     /**
278      * Are we allowed to send to the service?
279      */
280   int allow_send;
281
282 };
283
284
285 /**
286  * Implementation state for mesh's message queue.
287  */
288 struct MeshMQState
289 {
290   /**
291    * The current transmit handle, or NULL
292    * if no transmit is active.
293    */
294   struct GNUNET_MESH_TransmitHandle *th;
295
296   /**
297    * Channel to send the data over.
298    */
299   struct GNUNET_MESH_Channel *channel;
300 };
301
302
303 /******************************************************************************/
304 /***********************         DECLARATIONS         *************************/
305 /******************************************************************************/
306
307 /**
308  * Function called to send a message to the service.
309  * "buf" will be NULL and "size" zero if the socket was closed for writing in
310  * the meantime.
311  *
312  * @param cls closure, the mesh handle
313  * @param size number of bytes available in buf
314  * @param buf where the callee should write the connect message
315  * @return number of bytes written to buf
316  */
317 static size_t
318 send_callback (void *cls, size_t size, void *buf);
319
320
321 /******************************************************************************/
322 /***********************     AUXILIARY FUNCTIONS      *************************/
323 /******************************************************************************/
324
325 /**
326  * Check if transmission is a payload packet.
327  *
328  * @param th Transmission handle.
329  *
330  * @return GNUNET_YES if it is a payload packet,
331  *         GNUNET_NO if it is a mesh management packet.
332  */
333 static int
334 th_is_payload (struct GNUNET_MESH_TransmitHandle *th)
335 {
336   return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO;
337 }
338
339
340 /**
341  * Check whether there is any message ready in the queue and find the size.
342  *
343  * @param h Mesh handle.
344  *
345  * @return The size of the first ready message in the queue,
346  *         0 if there is none.
347  */
348 static size_t
349 message_ready_size (struct GNUNET_MESH_Handle *h)
350 {
351   struct GNUNET_MESH_TransmitHandle *th;
352   struct GNUNET_MESH_Channel *ch;
353
354   for (th = h->th_head; NULL != th; th = th->next)
355   {
356     ch = th->channel;
357     if (GNUNET_NO == th_is_payload (th))
358     {
359       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  message internal\n");
360       return th->size;
361     }
362     if (GNUNET_YES == ch->allow_send)
363     {
364       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  message payload ok\n");
365       return th->size;
366     }
367   }
368   return 0;
369 }
370
371
372 /**
373  * Get the channel handler for the channel specified by id from the given handle
374  * @param h Mesh handle
375  * @param chid ID of the wanted channel
376  * @return handle to the required channel or NULL if not found
377  */
378 static struct GNUNET_MESH_Channel *
379 retrieve_channel (struct GNUNET_MESH_Handle *h, MESH_ChannelNumber chid)
380 {
381   struct GNUNET_MESH_Channel *ch;
382
383   ch = h->channels_head;
384   while (ch != NULL)
385   {
386     if (ch->chid == chid)
387       return ch;
388     ch = ch->next;
389   }
390   return NULL;
391 }
392
393
394 /**
395  * Create a new channel and insert it in the channel list of the mesh handle
396  *
397  * @param h Mesh handle
398  * @param chid Desired chid of the channel, 0 to assign one automatically.
399  *
400  * @return Handle to the created channel.
401  */
402 static struct GNUNET_MESH_Channel *
403 create_channel (struct GNUNET_MESH_Handle *h, MESH_ChannelNumber chid)
404 {
405   struct GNUNET_MESH_Channel *ch;
406
407   ch = GNUNET_malloc (sizeof (struct GNUNET_MESH_Channel));
408   GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch);
409   ch->mesh = h;
410   if (0 == chid)
411   {
412     ch->chid = h->next_chid;
413     while (NULL != retrieve_channel (h, h->next_chid))
414     {
415       h->next_chid++;
416       h->next_chid &= ~GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
417       h->next_chid |= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
418     }
419   }
420   else
421   {
422     ch->chid = chid;
423   }
424   ch->allow_send = GNUNET_NO;
425   return ch;
426 }
427
428
429 /**
430  * Destroy the specified channel.
431  * - Destroys all peers, calling the disconnect callback on each if needed
432  * - Cancels all outgoing traffic for that channel, calling respective notifys
433  * - Calls cleaner if channel was inbound
434  * - Frees all memory used
435  *
436  * @param ch Pointer to the channel.
437  * @param call_cleaner Whether to call the cleaner handler.
438  *
439  * @return Handle to the required channel or NULL if not found.
440  */
441 static void
442 destroy_channel (struct GNUNET_MESH_Channel *ch, int call_cleaner)
443 {
444   struct GNUNET_MESH_Handle *h;
445   struct GNUNET_MESH_TransmitHandle *th;
446   struct GNUNET_MESH_TransmitHandle *next;
447
448   LOG (GNUNET_ERROR_TYPE_DEBUG, " destroy_channel %X\n", ch->chid);
449
450   if (NULL == ch)
451   {
452     GNUNET_break (0);
453     return;
454   }
455   h = ch->mesh;
456
457   GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch);
458
459   /* signal channel destruction */
460   if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner) )
461   {
462     LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cleaner\n");
463     h->cleaner (h->cls, ch, ch->ctx);
464   }
465
466   /* check that clients did not leave messages behind in the queue */
467   for (th = h->th_head; NULL != th; th = next)
468   {
469     next = th->next;
470     if (th->channel != ch)
471       continue;
472     /* Clients should have aborted their requests already.
473      * Management traffic should be ok, as clients can't cancel that.
474      * If the service crashed and we are reconnecting, it's ok.
475      */
476     GNUNET_break (GNUNET_NO == th_is_payload (th)
477                   || GNUNET_NO == h->in_receive);
478     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
479
480     /* clean up request */
481     if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
482       GNUNET_SCHEDULER_cancel (th->timeout_task);
483     GNUNET_free (th);
484   }
485
486   /* if there are no more pending requests with mesh service, cancel active request */
487   /* Note: this should be unnecessary... */
488   if ((0 == message_ready_size (h)) && (NULL != h->th))
489   {
490     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
491     h->th = NULL;
492   }
493
494   if (0 != ch->peer)
495     GNUNET_PEER_change_rc (ch->peer, -1);
496   GNUNET_free (ch);
497   return;
498 }
499
500
501 /**
502  * Notify client that the transmission has timed out
503  *
504  * @param cls closure
505  * @param tc task context
506  */
507 static void
508 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
509 {
510   struct GNUNET_MESH_TransmitHandle *th = cls;
511   struct GNUNET_MESH_Handle *mesh;
512
513   mesh = th->channel->mesh;
514   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
515   th->channel->packet_size = 0;
516   if (GNUNET_YES == th_is_payload (th))
517     th->notify (th->notify_cls, 0, NULL);
518   GNUNET_free (th);
519   if ((0 == message_ready_size (mesh)) && (NULL != mesh->th))
520   {
521     /* nothing ready to transmit, no point in asking for transmission */
522     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
523     mesh->th = NULL;
524   }
525 }
526
527
528 /**
529  * Add a transmit handle to the transmission queue and set the
530  * timeout if needed.
531  *
532  * @param h mesh handle with the queue head and tail
533  * @param th handle to the packet to be transmitted
534  */
535 static void
536 add_to_queue (struct GNUNET_MESH_Handle *h,
537               struct GNUNET_MESH_TransmitHandle *th)
538 {
539   GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th);
540   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == th->timeout.abs_value_us)
541     return;
542   th->timeout_task =
543       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
544                                     (th->timeout), &timeout_transmission, th);
545 }
546
547
548 /**
549  * Auxiliary function to send an already constructed packet to the service.
550  * Takes care of creating a new queue element, copying the message and
551  * calling the tmt_rdy function if necessary.
552  *
553  * @param h mesh handle
554  * @param msg message to transmit
555  * @param channel channel this send is related to (NULL if N/A)
556  */
557 static void
558 send_packet (struct GNUNET_MESH_Handle *h,
559              const struct GNUNET_MessageHeader *msg,
560              struct GNUNET_MESH_Channel *channel);
561
562
563 /**
564  * Send an ack on the channel to confirm the processing of a message.
565  *
566  * @param ch Channel on which to send the ACK.
567  */
568 static void
569 send_ack (struct GNUNET_MESH_Channel *ch)
570 {
571   struct GNUNET_MESH_LocalAck msg;
572
573   LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid);
574   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
575   msg.header.size = htons (sizeof (msg));
576   msg.channel_id = htonl (ch->chid);
577
578   send_packet (ch->mesh, &msg.header, ch);
579   return;
580 }
581
582
583
584 /**
585  * Reconnect callback: tries to reconnect again after a failer previous
586  * reconnecttion
587  * @param cls closure (mesh handle)
588  * @param tc task context
589  */
590 static void
591 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
592
593
594 /**
595  * Send a connect packet to the service with the applications and types
596  * requested by the user.
597  *
598  * @param h The mesh handle.
599  *
600  */
601 static void
602 send_connect (struct GNUNET_MESH_Handle *h)
603 {
604   size_t size;
605
606   size = sizeof (struct GNUNET_MESH_ClientConnect);
607   size += h->n_ports * sizeof (uint32_t);
608   {
609     char buf[size] GNUNET_ALIGN;
610     struct GNUNET_MESH_ClientConnect *msg;
611     uint32_t *ports;
612     uint16_t i;
613
614     /* build connection packet */
615     msg = (struct GNUNET_MESH_ClientConnect *) buf;
616     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
617     msg->header.size = htons (size);
618     ports = (uint32_t *) &msg[1];
619     for (i = 0; i < h->n_ports; i++)
620     {
621       ports[i] = htonl (h->ports[i]);
622       LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n",
623            h->ports[i]);
624     }
625     LOG (GNUNET_ERROR_TYPE_DEBUG,
626          "Sending %lu bytes long message with %u ports\n",
627          ntohs (msg->header.size), h->n_ports);
628     send_packet (h, &msg->header, NULL);
629   }
630 }
631
632
633 /**
634  * Reconnect to the service, retransmit all infomation to try to restore the
635  * original state.
636  *
637  * @param h handle to the mesh
638  *
639  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
640  */
641 static int
642 do_reconnect (struct GNUNET_MESH_Handle *h)
643 {
644   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
645   LOG (GNUNET_ERROR_TYPE_DEBUG, "*******   RECONNECT   *******\n");
646   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
647   LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h);
648   LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
649
650   /* disconnect */
651   if (NULL != h->th)
652   {
653     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
654     h->th = NULL;
655   }
656   if (NULL != h->client)
657   {
658     GNUNET_CLIENT_disconnect (h->client);
659   }
660
661   /* connect again */
662   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
663   if (h->client == NULL)
664   {
665     h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
666                                                       &reconnect_cbk, h);
667     h->reconnect_time =
668         GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
669                                   GNUNET_TIME_relative_multiply
670                                   (h->reconnect_time, 2));
671     LOG (GNUNET_ERROR_TYPE_DEBUG, "Next retry in %s\n",
672          GNUNET_STRINGS_relative_time_to_string (h->reconnect_time,
673                                                  GNUNET_NO));
674     GNUNET_break (0);
675     return GNUNET_NO;
676   }
677   else
678   {
679     h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
680   }
681   send_connect (h);
682   return GNUNET_YES;
683 }
684
685 /**
686  * Reconnect callback: tries to reconnect again after a failer previous
687  * reconnecttion
688  * @param cls closure (mesh handle)
689  * @param tc task context
690  */
691 static void
692 reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
693 {
694   struct GNUNET_MESH_Handle *h = cls;
695
696   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
697   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
698     return;
699   do_reconnect (h);
700 }
701
702
703 /**
704  * Reconnect to the service, retransmit all infomation to try to restore the
705  * original state.
706  *
707  * @param h handle to the mesh
708  *
709  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
710  */
711 static void
712 reconnect (struct GNUNET_MESH_Handle *h)
713 {
714   struct GNUNET_MESH_Channel *ch;
715   struct GNUNET_MESH_Channel *next;
716
717   LOG (GNUNET_ERROR_TYPE_DEBUG,
718        "Requested RECONNECT, destroying all channels\n");
719   h->in_receive = GNUNET_NO;
720   for (ch = h->channels_head; NULL != ch; ch = next)
721   {
722     next = ch->next;
723     destroy_channel (ch, GNUNET_YES);
724   }
725   if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task)
726     h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
727                                                       &reconnect_cbk, h);
728 }
729
730
731 /******************************************************************************/
732 /***********************      RECEIVE HANDLERS     ****************************/
733 /******************************************************************************/
734
735 /**
736  * Process the new channel notification and add it to the channels in the handle
737  *
738  * @param h     The mesh handle
739  * @param msg   A message with the details of the new incoming channel
740  */
741 static void
742 process_channel_created (struct GNUNET_MESH_Handle *h,
743                         const struct GNUNET_MESH_ChannelMessage *msg)
744 {
745   struct GNUNET_MESH_Channel *ch;
746   MESH_ChannelNumber chid;
747   uint32_t port;
748
749   chid = ntohl (msg->channel_id);
750   port = ntohl (msg->port);
751   LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X:%u\n", chid, port);
752   if (chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
753   {
754     GNUNET_break (0);
755     return;
756   }
757   if (NULL != h->new_channel)
758   {
759     void *ctx;
760
761     ch = create_channel (h, chid);
762     ch->allow_send = GNUNET_NO;
763     ch->peer = GNUNET_PEER_intern (&msg->peer);
764     ch->mesh = h;
765     ch->chid = chid;
766     ch->port = port;
767     ch->options = ntohl (msg->opt);
768
769     LOG (GNUNET_ERROR_TYPE_DEBUG, "  created channel %p\n", ch);
770     ctx = h->new_channel (h->cls, ch, &msg->peer, ch->port, ch->options);
771     if (NULL != ctx)
772       ch->ctx = ctx;
773     LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n");
774   }
775   else
776   {
777     struct GNUNET_MESH_ChannelMessage d_msg;
778
779     LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming channels\n");
780
781     d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
782     d_msg.header.size = htons (sizeof (struct GNUNET_MESH_ChannelMessage));
783     d_msg.channel_id = msg->channel_id;
784     memset (&d_msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
785     d_msg.port = 0;
786     d_msg.opt = 0;
787
788     send_packet (h, &d_msg.header, NULL);
789   }
790   return;
791 }
792
793
794 /**
795  * Process the channel destroy notification and free associated resources
796  *
797  * @param h     The mesh handle
798  * @param msg   A message with the details of the channel being destroyed
799  */
800 static void
801 process_channel_destroy (struct GNUNET_MESH_Handle *h,
802                          const struct GNUNET_MESH_ChannelMessage *msg)
803 {
804   struct GNUNET_MESH_Channel *ch;
805   MESH_ChannelNumber chid;
806
807   LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel Destroy received from service\n");
808   chid = ntohl (msg->channel_id);
809   ch = retrieve_channel (h, chid);
810
811   if (NULL == ch)
812   {
813     LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid);
814     return;
815   }
816   LOG (GNUNET_ERROR_TYPE_DEBUG, " destroying channel %X\n", ch->chid);
817   destroy_channel (ch, GNUNET_YES);
818 }
819
820
821 /**
822  * Process the incoming data packets, call appropriate handlers.
823  *
824  * @param h         The mesh handle
825  * @param message   A message encapsulating the data
826  */
827 static void
828 process_incoming_data (struct GNUNET_MESH_Handle *h,
829                        const struct GNUNET_MessageHeader *message)
830 {
831   const struct GNUNET_MessageHeader *payload;
832   const struct GNUNET_MESH_MessageHandler *handler;
833   struct GNUNET_MESH_LocalData *dmsg;
834   struct GNUNET_MESH_Channel *ch;
835   unsigned int i;
836   uint16_t type;
837
838   LOG (GNUNET_ERROR_TYPE_DEBUG,
839        "Got a data message!\n");
840   dmsg = (struct GNUNET_MESH_LocalData *) message;
841   ch = retrieve_channel (h, ntohl (dmsg->id));
842   payload = (struct GNUNET_MessageHeader *) &dmsg[1];
843   LOG (GNUNET_ERROR_TYPE_DEBUG,
844        "  %s data on channel %s [%X]\n",
845        ch->chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ? "fwd" : "bck",
846        GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id));
847   if (NULL == ch)
848   {
849     /* Channel was ignored/destroyed, probably service didn't get it yet */
850     LOG (GNUNET_ERROR_TYPE_DEBUG, "  ignored!\n");
851     return;
852   }
853   type = ntohs (payload->type);
854   LOG (GNUNET_ERROR_TYPE_DEBUG, "  payload type %u\n", type);
855   for (i = 0; i < h->n_handlers; i++)
856   {
857     handler = &h->message_handlers[i];
858     LOG (GNUNET_ERROR_TYPE_DEBUG,
859          "    checking handler for type %u\n",
860          handler->type);
861     if (handler->type == type)
862     {
863       if (GNUNET_OK !=
864           handler->callback (h->cls, ch, &ch->ctx, payload))
865       {
866         LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n");
867         GNUNET_MESH_channel_destroy (ch);
868         return;
869       }
870       else
871       {
872         LOG (GNUNET_ERROR_TYPE_DEBUG,
873              "callback completed successfully\n");
874         return;
875       }
876     }
877   }
878 }
879
880
881 /**
882  * Process a local ACK message, enabling the client to send
883  * more data to the service.
884  *
885  * @param h Mesh handle.
886  * @param message Message itself.
887  */
888 static void
889 process_ack (struct GNUNET_MESH_Handle *h,
890              const struct GNUNET_MessageHeader *message)
891 {
892   struct GNUNET_MESH_LocalAck *msg;
893   struct GNUNET_MESH_Channel *ch;
894   MESH_ChannelNumber chid;
895
896   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
897   msg = (struct GNUNET_MESH_LocalAck *) message;
898   chid = ntohl (msg->channel_id);
899     ch = retrieve_channel (h, chid);
900   if (NULL == ch)
901   {
902     LOG (GNUNET_ERROR_TYPE_WARNING, "ACK on unknown channel %X\n", chid);
903     return;
904   }
905   LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X!\n", ch->chid);
906   ch->allow_send = GNUNET_YES;
907   if (NULL == h->th && 0 < ch->packet_size)
908   {
909     LOG (GNUNET_ERROR_TYPE_DEBUG, "  tmt rdy was NULL, requesting!\n");
910     h->th =
911         GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size,
912                                              GNUNET_TIME_UNIT_FOREVER_REL,
913                                              GNUNET_YES, &send_callback, h);
914   }
915 }
916
917
918 /*
919  * Process a local reply about info on all channels, pass info to the user.
920  *
921  * @param h Mesh handle.
922  * @param message Message itself.
923  */
924 // static void
925 // process_get_channels (struct GNUNET_MESH_Handle *h,
926 //                      const struct GNUNET_MessageHeader *message)
927 // {
928 //   struct GNUNET_MESH_LocalMonitor *msg;
929 //
930 //   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
931 //
932 //   if (NULL == h->channels_cb)
933 //   {
934 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "  ignored\n");
935 //     return;
936 //   }
937 //
938 //   msg = (struct GNUNET_MESH_LocalMonitor *) message;
939 //   if (ntohs (message->size) !=
940 //       (sizeof (struct GNUNET_MESH_LocalMonitor) +
941 //        sizeof (struct GNUNET_PeerIdentity)))
942 //   {
943 //     GNUNET_break_op (0);
944 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
945 //                 "Get channels message: size %hu - expected %u\n",
946 //                 ntohs (message->size),
947 //                 sizeof (struct GNUNET_MESH_LocalMonitor));
948 //     return;
949 //   }
950 //   h->channels_cb (h->channels_cls,
951 //                   ntohl (msg->channel_id),
952 //                   &msg->owner,
953 //                   &msg->destination);
954 // }
955
956
957
958 /*
959  * Process a local monitor_channel reply, pass info to the user.
960  *
961  * @param h Mesh handle.
962  * @param message Message itself.
963  */
964 // static void
965 // process_show_channel (struct GNUNET_MESH_Handle *h,
966 //                      const struct GNUNET_MessageHeader *message)
967 // {
968 //   struct GNUNET_MESH_LocalMonitor *msg;
969 //   size_t esize;
970 //
971 //   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
972 //
973 //   if (NULL == h->channel_cb)
974 //   {
975 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "  ignored\n");
976 //     return;
977 //   }
978 //
979 //   /* Verify message sanity */
980 //   msg = (struct GNUNET_MESH_LocalMonitor *) message;
981 //   esize = sizeof (struct GNUNET_MESH_LocalMonitor);
982 //   if (ntohs (message->size) != esize)
983 //   {
984 //     GNUNET_break_op (0);
985 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
986 //                 "Show channel message: size %hu - expected %u\n",
987 //                 ntohs (message->size),
988 //                 esize);
989 //
990 //     h->channel_cb (h->channel_cls, NULL, NULL);
991 //     h->channel_cb = NULL;
992 //     h->channel_cls = NULL;
993 //
994 //     return;
995 //   }
996 //
997 //   h->channel_cb (h->channel_cls,
998 //                  &msg->destination,
999 //                  &msg->owner);
1000 // }
1001
1002
1003 /**
1004  * Function to process all messages received from the service
1005  *
1006  * @param cls closure
1007  * @param msg message received, NULL on timeout or fatal error
1008  */
1009 static void
1010 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
1011 {
1012   struct GNUNET_MESH_Handle *h = cls;
1013   uint16_t type;
1014
1015   if (msg == NULL)
1016   {
1017     LOG (GNUNET_ERROR_TYPE_DEBUG,
1018          "Mesh service disconnected, reconnecting\n", h);
1019     reconnect (h);
1020     return;
1021   }
1022   type = ntohs (msg->type);
1023   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
1024   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n",
1025        GM_m2s (type));
1026   switch (type)
1027   {
1028     /* Notify of a new incoming channel */
1029   case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
1030     process_channel_created (h, (struct GNUNET_MESH_ChannelMessage *) msg);
1031     break;
1032     /* Notify of a channel disconnection */
1033   case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: /* TODO separate(gid problem)*/
1034   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_NACK:
1035     process_channel_destroy (h, (struct GNUNET_MESH_ChannelMessage *) msg);
1036     break;
1037   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA:
1038     process_incoming_data (h, msg);
1039     break;
1040   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
1041     process_ack (h, msg);
1042     break;
1043 //   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS: DEPRECATED
1044 //     process_get_channels (h, msg);
1045 //     break;
1046 //   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL: DEPRECATED
1047 //     process_show_channel (h, msg);
1048 //     break;
1049   default:
1050     /* We shouldn't get any other packages, log and ignore */
1051     LOG (GNUNET_ERROR_TYPE_WARNING,
1052          "unsolicited message form service (type %s)\n",
1053          GM_m2s (ntohs (msg->type)));
1054   }
1055   LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
1056   if (GNUNET_YES == h->in_receive)
1057   {
1058     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1059                            GNUNET_TIME_UNIT_FOREVER_REL);
1060   }
1061   else
1062   {
1063     LOG (GNUNET_ERROR_TYPE_DEBUG,
1064          "in receive off, not calling CLIENT_receive\n");
1065   }
1066 }
1067
1068
1069 /******************************************************************************/
1070 /************************       SEND FUNCTIONS     ****************************/
1071 /******************************************************************************/
1072
1073 /**
1074  * Function called to send a message to the service.
1075  * "buf" will be NULL and "size" zero if the socket was closed for writing in
1076  * the meantime.
1077  *
1078  * @param cls closure, the mesh handle
1079  * @param size number of bytes available in buf
1080  * @param buf where the callee should write the connect message
1081  * @return number of bytes written to buf
1082  */
1083 static size_t
1084 send_callback (void *cls, size_t size, void *buf)
1085 {
1086   struct GNUNET_MESH_Handle *h = cls;
1087   struct GNUNET_MESH_TransmitHandle *th;
1088   struct GNUNET_MESH_TransmitHandle *next;
1089   struct GNUNET_MESH_Channel *ch;
1090   char *cbuf = buf;
1091   size_t tsize;
1092   size_t psize;
1093   size_t nsize;
1094
1095   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
1096   LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size);
1097   if ((0 == size) || (NULL == buf))
1098   {
1099     LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h);
1100     reconnect (h);
1101     h->th = NULL;
1102     return 0;
1103   }
1104   tsize = 0;
1105   next = h->th_head;
1106   nsize = message_ready_size (h);
1107   while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize))
1108   {
1109     ch = th->channel;
1110     if (GNUNET_YES == th_is_payload (th))
1111     {
1112       struct GNUNET_MESH_LocalData *dmsg;
1113       struct GNUNET_MessageHeader *mh;
1114
1115       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  payload\n");
1116       if (GNUNET_NO == ch->allow_send)
1117       {
1118         /* This channel is not ready to transmit yet, try next message */
1119         next = th->next;
1120         continue;
1121       }
1122       ch->packet_size = 0;
1123       GNUNET_assert (size >= th->size);
1124       dmsg = (struct GNUNET_MESH_LocalData *) cbuf;
1125       mh = (struct GNUNET_MessageHeader *) &dmsg[1];
1126       psize = th->notify (th->notify_cls,
1127                           size - sizeof (struct GNUNET_MESH_LocalData),
1128                           mh);
1129       if (psize > 0)
1130       {
1131         psize += sizeof (struct GNUNET_MESH_LocalData);
1132         GNUNET_assert (size >= psize);
1133         dmsg->header.size = htons (psize);
1134         dmsg->id = htonl (ch->chid);
1135         dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA);
1136         LOG (GNUNET_ERROR_TYPE_DEBUG, "#  payload type %s\n",
1137              GM_m2s (ntohs (mh->type)));
1138                 ch->allow_send = GNUNET_NO;
1139       }
1140       else
1141       {
1142         LOG (GNUNET_ERROR_TYPE_DEBUG,
1143              "#  callback returned size 0, "
1144              "application canceled transmission\n");
1145       }
1146     }
1147     else
1148     {
1149       struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1];
1150
1151       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  mesh internal traffic, type %s\n",
1152            GM_m2s (ntohs (mh->type)));
1153       memcpy (cbuf, &th[1], th->size);
1154       psize = th->size;
1155     }
1156     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1157       GNUNET_SCHEDULER_cancel (th->timeout_task);
1158     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1159     GNUNET_free (th);
1160     next = h->th_head;
1161     nsize = message_ready_size (h);
1162     cbuf += psize;
1163     size -= psize;
1164     tsize += psize;
1165   }
1166   LOG (GNUNET_ERROR_TYPE_DEBUG, "#  total size: %u\n", tsize);
1167   h->th = NULL;
1168   size = message_ready_size (h);
1169   if (0 != size)
1170   {
1171     LOG (GNUNET_ERROR_TYPE_DEBUG, "#  next size: %u\n", size);
1172     h->th =
1173         GNUNET_CLIENT_notify_transmit_ready (h->client, size,
1174                                              GNUNET_TIME_UNIT_FOREVER_REL,
1175                                              GNUNET_YES, &send_callback, h);
1176   }
1177   else
1178   {
1179     if (NULL != h->th_head)
1180       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  can't transmit any more\n");
1181     else
1182       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  nothing left to transmit\n");
1183   }
1184   if (GNUNET_NO == h->in_receive)
1185   {
1186     LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n");
1187     h->in_receive = GNUNET_YES;
1188     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1189                            GNUNET_TIME_UNIT_FOREVER_REL);
1190   }
1191   LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n");
1192   return tsize;
1193 }
1194
1195
1196 /**
1197  * Auxiliary function to send an already constructed packet to the service.
1198  * Takes care of creating a new queue element, copying the message and
1199  * calling the tmt_rdy function if necessary.
1200  *
1201  * @param h mesh handle
1202  * @param msg message to transmit
1203  * @param channel channel this send is related to (NULL if N/A)
1204  */
1205 static void
1206 send_packet (struct GNUNET_MESH_Handle *h,
1207              const struct GNUNET_MessageHeader *msg,
1208              struct GNUNET_MESH_Channel *channel)
1209 {
1210   struct GNUNET_MESH_TransmitHandle *th;
1211   size_t msize;
1212
1213   LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n",
1214        GM_m2s(ntohs(msg->type)));
1215   msize = ntohs (msg->size);
1216   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
1217   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1218   th->size = msize;
1219   th->channel = channel;
1220   memcpy (&th[1], msg, msize);
1221   add_to_queue (h, th);
1222   LOG (GNUNET_ERROR_TYPE_DEBUG, "  queued\n");
1223   if (NULL != h->th)
1224     return;
1225   LOG (GNUNET_ERROR_TYPE_DEBUG, "  calling ntfy tmt rdy for %u bytes\n", msize);
1226   h->th =
1227       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1228                                            GNUNET_TIME_UNIT_FOREVER_REL,
1229                                            GNUNET_YES, &send_callback, h);
1230 }
1231
1232
1233 /******************************************************************************/
1234 /**********************      API CALL DEFINITIONS     *************************/
1235 /******************************************************************************/
1236
1237 struct GNUNET_MESH_Handle *
1238 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
1239                      GNUNET_MESH_InboundChannelNotificationHandler new_channel,
1240                      GNUNET_MESH_ChannelEndHandler cleaner,
1241                      const struct GNUNET_MESH_MessageHandler *handlers,
1242                      const uint32_t *ports)
1243 {
1244   struct GNUNET_MESH_Handle *h;
1245
1246   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n");
1247   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1248   LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h);
1249   h->cfg = cfg;
1250   h->new_channel = new_channel;
1251   h->cleaner = cleaner;
1252   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1253   if (h->client == NULL)
1254   {
1255     GNUNET_break (0);
1256     GNUNET_free (h);
1257     return NULL;
1258   }
1259   h->cls = cls;
1260   h->message_handlers = handlers;
1261   h->ports = ports;
1262   h->next_chid = GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
1263   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1264   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1265
1266   if (NULL != ports && ports[0] != 0 && NULL == new_channel)
1267   {
1268     GNUNET_break (0);
1269     LOG (GNUNET_ERROR_TYPE_DEBUG,
1270          "no new channel handler given, ports parameter is useless!!\n");
1271   }
1272   if ((NULL == ports || ports[0] == 0) && NULL != new_channel)
1273   {
1274     GNUNET_break (0);
1275     LOG (GNUNET_ERROR_TYPE_DEBUG,
1276          "no ports given, new channel handler will never be called!!\n");
1277   }
1278   /* count handlers */
1279   for (h->n_handlers = 0;
1280        handlers && handlers[h->n_handlers].type;
1281        h->n_handlers++) ;
1282   for (h->n_ports = 0;
1283        ports && ports[h->n_ports];
1284        h->n_ports++) ;
1285   send_connect (h);
1286   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n");
1287   return h;
1288 }
1289
1290
1291 void
1292 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1293 {
1294   struct GNUNET_MESH_Channel *ch;
1295   struct GNUNET_MESH_Channel *aux;
1296   struct GNUNET_MESH_TransmitHandle *th;
1297
1298   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH DISCONNECT\n");
1299
1300   ch = handle->channels_head;
1301   while (NULL != ch)
1302   {
1303     aux = ch->next;
1304     if (ch->chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
1305     {
1306       GNUNET_break (0);
1307       LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid);
1308     }
1309     destroy_channel (ch, GNUNET_YES);
1310     ch = aux;
1311   }
1312   while ( (th = handle->th_head) != NULL)
1313   {
1314     struct GNUNET_MessageHeader *msg;
1315
1316     /* Make sure it is an allowed packet (everything else should have been
1317      * already canceled).
1318      */
1319     GNUNET_break (GNUNET_NO == th_is_payload (th));
1320     msg = (struct GNUNET_MessageHeader *) &th[1];
1321     switch (ntohs(msg->type))
1322     {
1323       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT:
1324       case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
1325       case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
1326       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS:
1327       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL:
1328         break;
1329       default:
1330         GNUNET_break (0);
1331         LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n",
1332              ntohs(msg->type));
1333     }
1334
1335     GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
1336     GNUNET_free (th);
1337   }
1338
1339   if (NULL != handle->th)
1340   {
1341     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1342     handle->th = NULL;
1343   }
1344   if (NULL != handle->client)
1345   {
1346     GNUNET_CLIENT_disconnect (handle->client);
1347     handle->client = NULL;
1348   }
1349   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
1350   {
1351     GNUNET_SCHEDULER_cancel(handle->reconnect_task);
1352     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1353   }
1354   GNUNET_free (handle);
1355 }
1356
1357
1358 /**
1359  * Create a new channel towards a remote peer.
1360  *
1361  * If the destination port is not open by any peer or the destination peer
1362  * does not accept the channel, #GNUNET_MESH_ChannelEndHandler will be called
1363  * for this channel.
1364  *
1365  * @param h mesh handle
1366  * @param channel_ctx client's channel context to associate with the channel
1367  * @param peer peer identity the channel should go to
1368  * @param port Port number.
1369  * @param options MeshOption flag field, with all desired option bits set to 1.
1370  *
1371  * @return handle to the channel
1372  */
1373 struct GNUNET_MESH_Channel *
1374 GNUNET_MESH_channel_create (struct GNUNET_MESH_Handle *h,
1375                             void *channel_ctx,
1376                             const struct GNUNET_PeerIdentity *peer,
1377                             uint32_t port,
1378                             enum GNUNET_MESH_ChannelOption options)
1379 {
1380   struct GNUNET_MESH_Channel *ch;
1381   struct GNUNET_MESH_ChannelMessage msg;
1382
1383   LOG (GNUNET_ERROR_TYPE_DEBUG,
1384        "Creating new channel to %s:%u\n",
1385        GNUNET_i2s (peer), port);
1386   ch = create_channel (h, 0);
1387   LOG (GNUNET_ERROR_TYPE_DEBUG, "  at %p\n", ch);
1388   LOG (GNUNET_ERROR_TYPE_DEBUG, "  number %X\n", ch->chid);
1389   ch->ctx = channel_ctx;
1390   ch->peer = GNUNET_PEER_intern (peer);
1391   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
1392   msg.header.size = htons (sizeof (struct GNUNET_MESH_ChannelMessage));
1393   msg.channel_id = htonl (ch->chid);
1394   msg.port = htonl (port);
1395   msg.peer = *peer;
1396   msg.opt = htonl (options);
1397   ch->allow_send = 0;
1398   send_packet (h, &msg.header, ch);
1399   return ch;
1400 }
1401
1402
1403 void
1404 GNUNET_MESH_channel_destroy (struct GNUNET_MESH_Channel *channel)
1405 {
1406   struct GNUNET_MESH_Handle *h;
1407   struct GNUNET_MESH_ChannelMessage msg;
1408   struct GNUNET_MESH_TransmitHandle *th;
1409
1410   LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n");
1411   h = channel->mesh;
1412
1413   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
1414   msg.header.size = htons (sizeof (struct GNUNET_MESH_ChannelMessage));
1415   msg.channel_id = htonl (channel->chid);
1416   memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
1417   msg.port = 0;
1418   msg.opt = 0;
1419   th = h->th_head;
1420   while (th != NULL)
1421   {
1422     struct GNUNET_MESH_TransmitHandle *aux;
1423     if (th->channel == channel)
1424     {
1425       aux = th->next;
1426       /* FIXME call the handler? */
1427       if (GNUNET_YES == th_is_payload (th))
1428         th->notify (th->notify_cls, 0, NULL);
1429       GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1430       GNUNET_free (th);
1431       th = aux;
1432     }
1433     else
1434       th = th->next;
1435   }
1436
1437   destroy_channel (channel, GNUNET_YES);
1438   send_packet (h, &msg.header, NULL);
1439 }
1440
1441
1442 /**
1443  * Get information about a channel.
1444  *
1445  * @param channel Channel handle.
1446  * @param option Query (GNUNET_MESH_OPTION_*).
1447  * @param ... dependant on option, currently not used
1448  *
1449  * @return Union with an answer to the query.
1450  */
1451 const union GNUNET_MESH_ChannelInfo *
1452 GNUNET_MESH_channel_get_info (struct GNUNET_MESH_Channel *channel,
1453                               enum GNUNET_MESH_ChannelOption option, ...)
1454 {
1455   static int bool_flag;
1456   const union GNUNET_MESH_ChannelInfo *ret;
1457
1458   switch (option)
1459   {
1460     case GNUNET_MESH_OPTION_NOBUFFER:
1461     case GNUNET_MESH_OPTION_RELIABLE:
1462     case GNUNET_MESH_OPTION_OOORDER:
1463       if (0 != (option & channel->options))
1464         bool_flag = GNUNET_YES;
1465       else
1466         bool_flag = GNUNET_NO;
1467       ret = (const union GNUNET_MESH_ChannelInfo *) &bool_flag;
1468       break;
1469     case GNUNET_MESH_OPTION_PEER:
1470       ret = (const union GNUNET_MESH_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer);
1471       break;
1472     default:
1473       GNUNET_break (0);
1474       return NULL;
1475   }
1476
1477   return ret;
1478 }
1479
1480 struct GNUNET_MESH_TransmitHandle *
1481 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Channel *channel, int cork,
1482                                    struct GNUNET_TIME_Relative maxdelay,
1483                                    size_t notify_size,
1484                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1485                                    void *notify_cls)
1486 {
1487   struct GNUNET_MESH_TransmitHandle *th;
1488
1489   GNUNET_assert (NULL != channel);
1490   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY\n");
1491   LOG (GNUNET_ERROR_TYPE_DEBUG, "    on channel %X\n", channel->chid);
1492   LOG (GNUNET_ERROR_TYPE_DEBUG, "    allow_send %d\n", channel->allow_send);
1493   if (channel->chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
1494     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to origin\n");
1495   else
1496     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to destination\n");
1497   LOG (GNUNET_ERROR_TYPE_DEBUG, "    payload size %u\n", notify_size);
1498   GNUNET_assert (NULL != notify);
1499   GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed
1500   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1501   th->channel = channel;
1502   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1503   th->size = notify_size + sizeof (struct GNUNET_MESH_LocalData);
1504   channel->packet_size = th->size;
1505   LOG (GNUNET_ERROR_TYPE_DEBUG, "    total size %u\n", th->size);
1506   th->notify = notify;
1507   th->notify_cls = notify_cls;
1508   add_to_queue (channel->mesh, th);
1509   if (NULL != channel->mesh->th)
1510     return th;
1511   if (GNUNET_NO == channel->allow_send)
1512     return th;
1513   LOG (GNUNET_ERROR_TYPE_DEBUG, "    call client notify tmt rdy\n");
1514   channel->mesh->th =
1515       GNUNET_CLIENT_notify_transmit_ready (channel->mesh->client, th->size,
1516                                            GNUNET_TIME_UNIT_FOREVER_REL,
1517                                            GNUNET_YES, &send_callback,
1518                                            channel->mesh);
1519   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY END\n");
1520   return th;
1521 }
1522
1523
1524 void
1525 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1526 {
1527   struct GNUNET_MESH_Handle *mesh;
1528
1529   th->channel->packet_size = 0;
1530   mesh = th->channel->mesh;
1531   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1532     GNUNET_SCHEDULER_cancel (th->timeout_task);
1533   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1534   GNUNET_free (th);
1535   if ((0 == message_ready_size (mesh)) && (NULL != mesh->th))
1536   {
1537     /* queue empty, no point in asking for transmission */
1538     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1539     mesh->th = NULL;
1540   }
1541 }
1542
1543
1544 void
1545 GNUNET_MESH_receive_done (struct GNUNET_MESH_Channel *channel)
1546 {
1547   send_ack (channel);
1548 }
1549
1550
1551 /**
1552  * Request information about the running mesh peer.
1553  * The callback will be called for every channel known to the service,
1554  * listing all active peers that blong to the channel.
1555  *
1556  * If called again on the same handle, it will overwrite the previous
1557  * callback and cls. To retrieve the cls, monitor_cancel must be
1558  * called first.
1559  *
1560  * WARNING: unstable API, likely to change in the future!
1561  *
1562  * @param h Handle to the mesh peer.
1563  * @param callback Function to call with the requested data.
1564  * @param callback_cls Closure for @c callback.
1565  */
1566 void
1567 GNUNET_MESH_get_channels (struct GNUNET_MESH_Handle *h,
1568                          GNUNET_MESH_ChannelsCB callback,
1569                          void *callback_cls)
1570 {
1571   struct GNUNET_MessageHeader msg;
1572
1573   msg.size = htons (sizeof (msg));
1574   msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS);
1575   send_packet (h, &msg, NULL);
1576   h->channels_cb = callback;
1577   h->channels_cls = callback_cls;
1578 }
1579
1580
1581 /**
1582  * Cancel a monitor request. The monitor callback will not be called.
1583  *
1584  * @param h Mesh handle.
1585  *
1586  * @return Closure given to GNUNET_MESH_monitor, if any.
1587  */
1588 void *
1589 GNUNET_MESH_get_channels_cancel (struct GNUNET_MESH_Handle *h)
1590 {
1591   void *cls;
1592
1593   cls = h->channels_cls;
1594   h->channels_cb = NULL;
1595   h->channels_cls = NULL;
1596   return cls;
1597 }
1598
1599
1600 /**
1601  * Request information about a specific channel of the running mesh peer.
1602  *
1603  * WARNING: unstable API, likely to change in the future!
1604  * FIXME Add destination option.
1605  *
1606  * @param h Handle to the mesh peer.
1607  * @param initiator ID of the owner of the channel.
1608  * @param channel_number Channel number.
1609  * @param callback Function to call with the requested data.
1610  * @param callback_cls Closure for @c callback.
1611  */
1612 void
1613 GNUNET_MESH_show_channel (struct GNUNET_MESH_Handle *h,
1614                          struct GNUNET_PeerIdentity *initiator,
1615                          unsigned int channel_number,
1616                          GNUNET_MESH_ChannelCB callback,
1617                          void *callback_cls)
1618 {
1619   struct GNUNET_MESH_LocalMonitor msg;
1620
1621   msg.header.size = htons (sizeof (msg));
1622   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL);
1623   msg.owner = *initiator;
1624   msg.channel_id = htonl (channel_number);
1625   msg.reserved = 0;
1626   send_packet (h, &msg.header, NULL);
1627   h->channel_cb = callback;
1628   h->channel_cls = callback_cls;
1629 }
1630
1631
1632 /**
1633  * Function called to notify a client about the connection
1634  * begin ready to queue more data.  "buf" will be
1635  * NULL and "size" zero if the connection was closed for
1636  * writing in the meantime.
1637  *
1638  * @param cls closure
1639  * @param size number of bytes available in buf
1640  * @param buf where the callee should write the message
1641  * @return number of bytes written to buf
1642  */
1643 static size_t
1644 mesh_mq_ntr (void *cls, size_t size,
1645              void *buf)
1646 {
1647   struct GNUNET_MQ_Handle *mq = cls;
1648   struct MeshMQState *state = GNUNET_MQ_impl_state (mq);
1649   const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
1650   uint16_t msize;
1651
1652   state->th = NULL;
1653   if (NULL == buf)
1654   {
1655     GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE);
1656     return 0;
1657   }
1658   msize = ntohs (msg->size);
1659   GNUNET_assert (msize <= size);
1660   memcpy (buf, msg, msize);
1661   GNUNET_MQ_impl_send_continue (mq);
1662   return msize;
1663 }
1664
1665
1666 /**
1667  * Signature of functions implementing the
1668  * sending functionality of a message queue.
1669  *
1670  * @param mq the message queue
1671  * @param msg the message to send
1672  * @param impl_state state of the implementation
1673  */
1674 static void
1675 mesh_mq_send_impl (struct GNUNET_MQ_Handle *mq,
1676                    const struct GNUNET_MessageHeader *msg, void *impl_state)
1677 {
1678   struct MeshMQState *state = impl_state;
1679
1680   GNUNET_assert (NULL == state->th);
1681   state->th =
1682       GNUNET_MESH_notify_transmit_ready (state->channel,
1683                                          /* FIXME: add option for corking */
1684                                          GNUNET_NO,
1685                                          GNUNET_TIME_UNIT_FOREVER_REL,
1686                                          ntohs (msg->size),
1687                                          mesh_mq_ntr, mq);
1688
1689 }
1690
1691
1692 /**
1693  * Signature of functions implementing the
1694  * destruction of a message queue.
1695  * Implementations must not free 'mq', but should
1696  * take care of 'impl_state'.
1697  *
1698  * @param mq the message queue to destroy
1699  * @param impl_state state of the implementation
1700  */
1701 static void
1702 mesh_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
1703 {
1704   struct MeshMQState *state = impl_state;
1705
1706   if (NULL != state->th)
1707     GNUNET_MESH_notify_transmit_ready_cancel (state->th);
1708
1709   GNUNET_free (state);
1710 }
1711
1712
1713 /**
1714  * Create a message queue for a mesh channel.
1715  * The message queue can only be used to transmit messages,
1716  * not to receive them.
1717  *
1718  * @param channel the channel to create the message qeue for
1719  * @return a message queue to messages over the channel
1720  */
1721 struct GNUNET_MQ_Handle *
1722 GNUNET_MESH_mq_create (struct GNUNET_MESH_Channel *channel)
1723 {
1724   struct GNUNET_MQ_Handle *mq;
1725   struct MeshMQState *state;
1726
1727   state = GNUNET_new (struct MeshMQState);
1728   state->channel = channel;
1729
1730   mq = GNUNET_MQ_queue_for_callbacks (mesh_mq_send_impl,
1731                                       mesh_mq_destroy_impl,
1732                                       NULL, /* FIXME: cancel impl. */
1733                                       state,
1734                                       NULL, /* no msg handlers */
1735                                       NULL, /* no err handlers */
1736                                       NULL); /* no handler cls */
1737   return mq;
1738 }
1739