specify proper access control rules for conversation service
[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_new (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   size_t size;
836   unsigned int i;
837   uint16_t type;
838
839   LOG (GNUNET_ERROR_TYPE_DEBUG, "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, "  %s data on channel %s [%X]\n",
844        GM_f2s (ch->chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV),
845        GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id));
846
847   size = ntohs (message->size);
848   LOG (GNUNET_ERROR_TYPE_DEBUG, "  %u bytes\n", size);
849
850   if (NULL == ch)
851   {
852     /* Channel was ignored/destroyed, probably service didn't get it yet */
853     LOG (GNUNET_ERROR_TYPE_DEBUG, "  ignored!\n");
854     return;
855   }
856   type = ntohs (payload->type);
857   size = ntohs (payload->size);
858   LOG (GNUNET_ERROR_TYPE_DEBUG, "  payload type %s\n", GM_m2s (type));
859   for (i = 0; i < h->n_handlers; i++)
860   {
861     handler = &h->message_handlers[i];
862     LOG (GNUNET_ERROR_TYPE_DEBUG, "    checking handler for type %u\n",
863          handler->type);
864     if (handler->type == type)
865     {
866       if (GNUNET_OK !=
867           handler->callback (h->cls, ch, &ch->ctx, payload))
868       {
869         LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n");
870         GNUNET_MESH_channel_destroy (ch);
871         return;
872       }
873       else
874       {
875         LOG (GNUNET_ERROR_TYPE_DEBUG,
876              "callback completed successfully\n");
877         return;
878       }
879     }
880   }
881 }
882
883
884 /**
885  * Process a local ACK message, enabling the client to send
886  * more data to the service.
887  *
888  * @param h Mesh handle.
889  * @param message Message itself.
890  */
891 static void
892 process_ack (struct GNUNET_MESH_Handle *h,
893              const struct GNUNET_MessageHeader *message)
894 {
895   struct GNUNET_MESH_LocalAck *msg;
896   struct GNUNET_MESH_Channel *ch;
897   MESH_ChannelNumber chid;
898
899   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
900   msg = (struct GNUNET_MESH_LocalAck *) message;
901   chid = ntohl (msg->channel_id);
902   ch = retrieve_channel (h, chid);
903   if (NULL == ch)
904   {
905     LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid);
906     return;
907   }
908   LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X!\n", ch->chid);
909   ch->allow_send = GNUNET_YES;
910   if (NULL == h->th && 0 < ch->packet_size)
911   {
912     LOG (GNUNET_ERROR_TYPE_DEBUG, "  tmt rdy was NULL, requesting!\n");
913     h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size,
914                                                  GNUNET_TIME_UNIT_FOREVER_REL,
915                                                  GNUNET_YES, &send_callback, h);
916   }
917 }
918
919
920 /*
921  * Process a local reply about info on all channels, pass info to the user.
922  *
923  * @param h Mesh handle.
924  * @param message Message itself.
925  */
926 // static void
927 // process_get_channels (struct GNUNET_MESH_Handle *h,
928 //                      const struct GNUNET_MessageHeader *message)
929 // {
930 //   struct GNUNET_MESH_LocalMonitor *msg;
931 //
932 //   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
933 //
934 //   if (NULL == h->channels_cb)
935 //   {
936 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "  ignored\n");
937 //     return;
938 //   }
939 //
940 //   msg = (struct GNUNET_MESH_LocalMonitor *) message;
941 //   if (ntohs (message->size) !=
942 //       (sizeof (struct GNUNET_MESH_LocalMonitor) +
943 //        sizeof (struct GNUNET_PeerIdentity)))
944 //   {
945 //     GNUNET_break_op (0);
946 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
947 //                 "Get channels message: size %hu - expected %u\n",
948 //                 ntohs (message->size),
949 //                 sizeof (struct GNUNET_MESH_LocalMonitor));
950 //     return;
951 //   }
952 //   h->channels_cb (h->channels_cls,
953 //                   ntohl (msg->channel_id),
954 //                   &msg->owner,
955 //                   &msg->destination);
956 // }
957
958
959
960 /*
961  * Process a local monitor_channel reply, pass info to the user.
962  *
963  * @param h Mesh handle.
964  * @param message Message itself.
965  */
966 // static void
967 // process_show_channel (struct GNUNET_MESH_Handle *h,
968 //                      const struct GNUNET_MessageHeader *message)
969 // {
970 //   struct GNUNET_MESH_LocalMonitor *msg;
971 //   size_t esize;
972 //
973 //   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
974 //
975 //   if (NULL == h->channel_cb)
976 //   {
977 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "  ignored\n");
978 //     return;
979 //   }
980 //
981 //   /* Verify message sanity */
982 //   msg = (struct GNUNET_MESH_LocalMonitor *) message;
983 //   esize = sizeof (struct GNUNET_MESH_LocalMonitor);
984 //   if (ntohs (message->size) != esize)
985 //   {
986 //     GNUNET_break_op (0);
987 //     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
988 //                 "Show channel message: size %hu - expected %u\n",
989 //                 ntohs (message->size),
990 //                 esize);
991 //
992 //     h->channel_cb (h->channel_cls, NULL, NULL);
993 //     h->channel_cb = NULL;
994 //     h->channel_cls = NULL;
995 //
996 //     return;
997 //   }
998 //
999 //   h->channel_cb (h->channel_cls,
1000 //                  &msg->destination,
1001 //                  &msg->owner);
1002 // }
1003
1004
1005 /**
1006  * Function to process all messages received from the service
1007  *
1008  * @param cls closure
1009  * @param msg message received, NULL on timeout or fatal error
1010  */
1011 static void
1012 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
1013 {
1014   struct GNUNET_MESH_Handle *h = cls;
1015   uint16_t type;
1016
1017   if (msg == NULL)
1018   {
1019     LOG (GNUNET_ERROR_TYPE_DEBUG,
1020          "Mesh service disconnected, reconnecting\n", h);
1021     reconnect (h);
1022     return;
1023   }
1024   type = ntohs (msg->type);
1025   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
1026   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n",
1027        GM_m2s (type));
1028   switch (type)
1029   {
1030     /* Notify of a new incoming channel */
1031   case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
1032     process_channel_created (h, (struct GNUNET_MESH_ChannelMessage *) msg);
1033     break;
1034     /* Notify of a channel disconnection */
1035   case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY: /* TODO separate(gid problem)*/
1036   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_NACK:
1037     process_channel_destroy (h, (struct GNUNET_MESH_ChannelMessage *) msg);
1038     break;
1039   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA:
1040     process_incoming_data (h, msg);
1041     break;
1042   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
1043     process_ack (h, msg);
1044     break;
1045 //   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS: DEPRECATED
1046 //     process_get_channels (h, msg);
1047 //     break;
1048 //   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL: DEPRECATED
1049 //     process_show_channel (h, msg);
1050 //     break;
1051   default:
1052     /* We shouldn't get any other packages, log and ignore */
1053     LOG (GNUNET_ERROR_TYPE_WARNING,
1054          "unsolicited message form service (type %s)\n",
1055          GM_m2s (ntohs (msg->type)));
1056   }
1057   LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
1058   if (GNUNET_YES == h->in_receive)
1059   {
1060     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1061                            GNUNET_TIME_UNIT_FOREVER_REL);
1062   }
1063   else
1064   {
1065     LOG (GNUNET_ERROR_TYPE_DEBUG,
1066          "in receive off, not calling CLIENT_receive\n");
1067   }
1068 }
1069
1070
1071 /******************************************************************************/
1072 /************************       SEND FUNCTIONS     ****************************/
1073 /******************************************************************************/
1074
1075 /**
1076  * Function called to send a message to the service.
1077  * "buf" will be NULL and "size" zero if the socket was closed for writing in
1078  * the meantime.
1079  *
1080  * @param cls closure, the mesh handle
1081  * @param size number of bytes available in buf
1082  * @param buf where the callee should write the connect message
1083  * @return number of bytes written to buf
1084  */
1085 static size_t
1086 send_callback (void *cls, size_t size, void *buf)
1087 {
1088   struct GNUNET_MESH_Handle *h = cls;
1089   struct GNUNET_MESH_TransmitHandle *th;
1090   struct GNUNET_MESH_TransmitHandle *next;
1091   struct GNUNET_MESH_Channel *ch;
1092   char *cbuf = buf;
1093   size_t tsize;
1094   size_t psize;
1095   size_t nsize;
1096
1097   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
1098   LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size);
1099   if ((0 == size) || (NULL == buf))
1100   {
1101     LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h);
1102     reconnect (h);
1103     h->th = NULL;
1104     return 0;
1105   }
1106   tsize = 0;
1107   next = h->th_head;
1108   nsize = message_ready_size (h);
1109   while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize))
1110   {
1111     ch = th->channel;
1112     if (GNUNET_YES == th_is_payload (th))
1113     {
1114       struct GNUNET_MESH_LocalData *dmsg;
1115       struct GNUNET_MessageHeader *mh;
1116
1117       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  payload\n");
1118       if (GNUNET_NO == ch->allow_send)
1119       {
1120         /* This channel is not ready to transmit yet, try next message */
1121         next = th->next;
1122         continue;
1123       }
1124       ch->packet_size = 0;
1125       GNUNET_assert (size >= th->size);
1126       dmsg = (struct GNUNET_MESH_LocalData *) cbuf;
1127       mh = (struct GNUNET_MessageHeader *) &dmsg[1];
1128       psize = th->notify (th->notify_cls,
1129                           size - sizeof (struct GNUNET_MESH_LocalData),
1130                           mh);
1131       if (psize > 0)
1132       {
1133         psize += sizeof (struct GNUNET_MESH_LocalData);
1134         GNUNET_assert (size >= psize);
1135         dmsg->header.size = htons (psize);
1136         dmsg->id = htonl (ch->chid);
1137         dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA);
1138         LOG (GNUNET_ERROR_TYPE_DEBUG, "#  payload type %s\n",
1139              GM_m2s (ntohs (mh->type)));
1140                 ch->allow_send = GNUNET_NO;
1141       }
1142       else
1143       {
1144         LOG (GNUNET_ERROR_TYPE_DEBUG,
1145              "#  callback returned size 0, "
1146              "application canceled transmission\n");
1147       }
1148     }
1149     else
1150     {
1151       struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1];
1152
1153       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  mesh internal traffic, type %s\n",
1154            GM_m2s (ntohs (mh->type)));
1155       memcpy (cbuf, &th[1], th->size);
1156       psize = th->size;
1157     }
1158     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1159       GNUNET_SCHEDULER_cancel (th->timeout_task);
1160     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1161     GNUNET_free (th);
1162     next = h->th_head;
1163     nsize = message_ready_size (h);
1164     cbuf += psize;
1165     size -= psize;
1166     tsize += psize;
1167   }
1168   LOG (GNUNET_ERROR_TYPE_DEBUG, "#  total size: %u\n", tsize);
1169   h->th = NULL;
1170   size = message_ready_size (h);
1171   if (0 != size)
1172   {
1173     LOG (GNUNET_ERROR_TYPE_DEBUG, "#  next size: %u\n", size);
1174     h->th =
1175         GNUNET_CLIENT_notify_transmit_ready (h->client, size,
1176                                              GNUNET_TIME_UNIT_FOREVER_REL,
1177                                              GNUNET_YES, &send_callback, h);
1178   }
1179   else
1180   {
1181     if (NULL != h->th_head)
1182       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  can't transmit any more\n");
1183     else
1184       LOG (GNUNET_ERROR_TYPE_DEBUG, "#  nothing left to transmit\n");
1185   }
1186   if (GNUNET_NO == h->in_receive)
1187   {
1188     LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n");
1189     h->in_receive = GNUNET_YES;
1190     GNUNET_CLIENT_receive (h->client, &msg_received, h,
1191                            GNUNET_TIME_UNIT_FOREVER_REL);
1192   }
1193   LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n");
1194   return tsize;
1195 }
1196
1197
1198 /**
1199  * Auxiliary function to send an already constructed packet to the service.
1200  * Takes care of creating a new queue element, copying the message and
1201  * calling the tmt_rdy function if necessary.
1202  *
1203  * @param h mesh handle
1204  * @param msg message to transmit
1205  * @param channel channel this send is related to (NULL if N/A)
1206  */
1207 static void
1208 send_packet (struct GNUNET_MESH_Handle *h,
1209              const struct GNUNET_MessageHeader *msg,
1210              struct GNUNET_MESH_Channel *channel)
1211 {
1212   struct GNUNET_MESH_TransmitHandle *th;
1213   size_t msize;
1214
1215   LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n",
1216        GM_m2s(ntohs(msg->type)));
1217   msize = ntohs (msg->size);
1218   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
1219   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1220   th->size = msize;
1221   th->channel = channel;
1222   memcpy (&th[1], msg, msize);
1223   add_to_queue (h, th);
1224   LOG (GNUNET_ERROR_TYPE_DEBUG, "  queued\n");
1225   if (NULL != h->th)
1226     return;
1227   LOG (GNUNET_ERROR_TYPE_DEBUG, "  calling ntfy tmt rdy for %u bytes\n", msize);
1228   h->th =
1229       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
1230                                            GNUNET_TIME_UNIT_FOREVER_REL,
1231                                            GNUNET_YES, &send_callback, h);
1232 }
1233
1234
1235 /******************************************************************************/
1236 /**********************      API CALL DEFINITIONS     *************************/
1237 /******************************************************************************/
1238
1239 struct GNUNET_MESH_Handle *
1240 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
1241                      GNUNET_MESH_InboundChannelNotificationHandler new_channel,
1242                      GNUNET_MESH_ChannelEndHandler cleaner,
1243                      const struct GNUNET_MESH_MessageHandler *handlers,
1244                      const uint32_t *ports)
1245 {
1246   struct GNUNET_MESH_Handle *h;
1247
1248   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n");
1249   h = GNUNET_new (struct GNUNET_MESH_Handle);
1250   LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h);
1251   h->cfg = cfg;
1252   h->new_channel = new_channel;
1253   h->cleaner = cleaner;
1254   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1255   if (h->client == NULL)
1256   {
1257     GNUNET_break (0);
1258     GNUNET_free (h);
1259     return NULL;
1260   }
1261   h->cls = cls;
1262   h->message_handlers = handlers;
1263   h->ports = ports;
1264   h->next_chid = GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
1265   h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1266   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1267
1268   if (NULL != ports && ports[0] != 0 && NULL == new_channel)
1269   {
1270     GNUNET_break (0);
1271     LOG (GNUNET_ERROR_TYPE_DEBUG,
1272          "no new channel handler given, ports parameter is useless!!\n");
1273   }
1274   if ((NULL == ports || ports[0] == 0) && NULL != new_channel)
1275   {
1276     GNUNET_break (0);
1277     LOG (GNUNET_ERROR_TYPE_DEBUG,
1278          "no ports given, new channel handler will never be called!!\n");
1279   }
1280   /* count handlers */
1281   for (h->n_handlers = 0;
1282        handlers && handlers[h->n_handlers].type;
1283        h->n_handlers++) ;
1284   for (h->n_ports = 0;
1285        ports && ports[h->n_ports];
1286        h->n_ports++) ;
1287   send_connect (h);
1288   LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n");
1289   return h;
1290 }
1291
1292
1293 void
1294 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1295 {
1296   struct GNUNET_MESH_Channel *ch;
1297   struct GNUNET_MESH_Channel *aux;
1298   struct GNUNET_MESH_TransmitHandle *th;
1299
1300   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH DISCONNECT\n");
1301
1302   ch = handle->channels_head;
1303   while (NULL != ch)
1304   {
1305     aux = ch->next;
1306     if (ch->chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
1307     {
1308       GNUNET_break (0);
1309       LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid);
1310     }
1311     destroy_channel (ch, GNUNET_YES);
1312     ch = aux;
1313   }
1314   while ( (th = handle->th_head) != NULL)
1315   {
1316     struct GNUNET_MessageHeader *msg;
1317
1318     /* Make sure it is an allowed packet (everything else should have been
1319      * already canceled).
1320      */
1321     GNUNET_break (GNUNET_NO == th_is_payload (th));
1322     msg = (struct GNUNET_MessageHeader *) &th[1];
1323     switch (ntohs(msg->type))
1324     {
1325       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT:
1326       case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
1327       case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
1328       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS:
1329       case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL:
1330         break;
1331       default:
1332         GNUNET_break (0);
1333         LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n",
1334              ntohs(msg->type));
1335     }
1336
1337     GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
1338     GNUNET_free (th);
1339   }
1340
1341   if (NULL != handle->th)
1342   {
1343     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1344     handle->th = NULL;
1345   }
1346   if (NULL != handle->client)
1347   {
1348     GNUNET_CLIENT_disconnect (handle->client);
1349     handle->client = NULL;
1350   }
1351   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
1352   {
1353     GNUNET_SCHEDULER_cancel(handle->reconnect_task);
1354     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
1355   }
1356   GNUNET_free (handle);
1357 }
1358
1359
1360 /**
1361  * Create a new channel towards a remote peer.
1362  *
1363  * If the destination port is not open by any peer or the destination peer
1364  * does not accept the channel, #GNUNET_MESH_ChannelEndHandler will be called
1365  * for this channel.
1366  *
1367  * @param h mesh handle
1368  * @param channel_ctx client's channel context to associate with the channel
1369  * @param peer peer identity the channel should go to
1370  * @param port Port number.
1371  * @param options MeshOption flag field, with all desired option bits set to 1.
1372  *
1373  * @return handle to the channel
1374  */
1375 struct GNUNET_MESH_Channel *
1376 GNUNET_MESH_channel_create (struct GNUNET_MESH_Handle *h,
1377                             void *channel_ctx,
1378                             const struct GNUNET_PeerIdentity *peer,
1379                             uint32_t port,
1380                             enum GNUNET_MESH_ChannelOption options)
1381 {
1382   struct GNUNET_MESH_Channel *ch;
1383   struct GNUNET_MESH_ChannelMessage msg;
1384
1385   LOG (GNUNET_ERROR_TYPE_DEBUG,
1386        "Creating new channel to %s:%u\n",
1387        GNUNET_i2s (peer), port);
1388   ch = create_channel (h, 0);
1389   LOG (GNUNET_ERROR_TYPE_DEBUG, "  at %p\n", ch);
1390   LOG (GNUNET_ERROR_TYPE_DEBUG, "  number %X\n", ch->chid);
1391   ch->ctx = channel_ctx;
1392   ch->peer = GNUNET_PEER_intern (peer);
1393   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
1394   msg.header.size = htons (sizeof (struct GNUNET_MESH_ChannelMessage));
1395   msg.channel_id = htonl (ch->chid);
1396   msg.port = htonl (port);
1397   msg.peer = *peer;
1398   msg.opt = htonl (options);
1399   ch->allow_send = 0;
1400   send_packet (h, &msg.header, ch);
1401   return ch;
1402 }
1403
1404
1405 void
1406 GNUNET_MESH_channel_destroy (struct GNUNET_MESH_Channel *channel)
1407 {
1408   struct GNUNET_MESH_Handle *h;
1409   struct GNUNET_MESH_ChannelMessage msg;
1410   struct GNUNET_MESH_TransmitHandle *th;
1411
1412   LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n");
1413   h = channel->mesh;
1414
1415   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
1416   msg.header.size = htons (sizeof (struct GNUNET_MESH_ChannelMessage));
1417   msg.channel_id = htonl (channel->chid);
1418   memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
1419   msg.port = 0;
1420   msg.opt = 0;
1421   th = h->th_head;
1422   while (th != NULL)
1423   {
1424     struct GNUNET_MESH_TransmitHandle *aux;
1425     if (th->channel == channel)
1426     {
1427       aux = th->next;
1428       /* FIXME call the handler? */
1429       if (GNUNET_YES == th_is_payload (th))
1430         th->notify (th->notify_cls, 0, NULL);
1431       GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
1432       GNUNET_free (th);
1433       th = aux;
1434     }
1435     else
1436       th = th->next;
1437   }
1438
1439   destroy_channel (channel, GNUNET_YES);
1440   send_packet (h, &msg.header, NULL);
1441 }
1442
1443
1444 /**
1445  * Get information about a channel.
1446  *
1447  * @param channel Channel handle.
1448  * @param option Query (GNUNET_MESH_OPTION_*).
1449  * @param ... dependant on option, currently not used
1450  *
1451  * @return Union with an answer to the query.
1452  */
1453 const union GNUNET_MESH_ChannelInfo *
1454 GNUNET_MESH_channel_get_info (struct GNUNET_MESH_Channel *channel,
1455                               enum GNUNET_MESH_ChannelOption option, ...)
1456 {
1457   static int bool_flag;
1458   const union GNUNET_MESH_ChannelInfo *ret;
1459
1460   switch (option)
1461   {
1462     case GNUNET_MESH_OPTION_NOBUFFER:
1463     case GNUNET_MESH_OPTION_RELIABLE:
1464     case GNUNET_MESH_OPTION_OOORDER:
1465       if (0 != (option & channel->options))
1466         bool_flag = GNUNET_YES;
1467       else
1468         bool_flag = GNUNET_NO;
1469       ret = (const union GNUNET_MESH_ChannelInfo *) &bool_flag;
1470       break;
1471     case GNUNET_MESH_OPTION_PEER:
1472       ret = (const union GNUNET_MESH_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer);
1473       break;
1474     default:
1475       GNUNET_break (0);
1476       return NULL;
1477   }
1478
1479   return ret;
1480 }
1481
1482 struct GNUNET_MESH_TransmitHandle *
1483 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Channel *channel, int cork,
1484                                    struct GNUNET_TIME_Relative maxdelay,
1485                                    size_t notify_size,
1486                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1487                                    void *notify_cls)
1488 {
1489   struct GNUNET_MESH_TransmitHandle *th;
1490
1491   GNUNET_assert (NULL != channel);
1492   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY\n");
1493   LOG (GNUNET_ERROR_TYPE_DEBUG, "    on channel %X\n", channel->chid);
1494   LOG (GNUNET_ERROR_TYPE_DEBUG, "    allow_send %d\n", channel->allow_send);
1495   if (channel->chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
1496     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to origin\n");
1497   else
1498     LOG (GNUNET_ERROR_TYPE_DEBUG, "    to destination\n");
1499   LOG (GNUNET_ERROR_TYPE_DEBUG, "    payload size %u\n", notify_size);
1500   GNUNET_assert (NULL != notify);
1501   GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed
1502   th = GNUNET_new (struct GNUNET_MESH_TransmitHandle);
1503   th->channel = channel;
1504   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1505   th->size = notify_size + sizeof (struct GNUNET_MESH_LocalData);
1506   channel->packet_size = th->size;
1507   LOG (GNUNET_ERROR_TYPE_DEBUG, "    total size %u\n", th->size);
1508   th->notify = notify;
1509   th->notify_cls = notify_cls;
1510   add_to_queue (channel->mesh, th);
1511   if (NULL != channel->mesh->th)
1512     return th;
1513   if (GNUNET_NO == channel->allow_send)
1514     return th;
1515   LOG (GNUNET_ERROR_TYPE_DEBUG, "    call client notify tmt rdy\n");
1516   channel->mesh->th =
1517       GNUNET_CLIENT_notify_transmit_ready (channel->mesh->client, th->size,
1518                                            GNUNET_TIME_UNIT_FOREVER_REL,
1519                                            GNUNET_YES, &send_callback,
1520                                            channel->mesh);
1521   LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY END\n");
1522   return th;
1523 }
1524
1525
1526 void
1527 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1528 {
1529   struct GNUNET_MESH_Handle *mesh;
1530
1531   th->channel->packet_size = 0;
1532   mesh = th->channel->mesh;
1533   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1534     GNUNET_SCHEDULER_cancel (th->timeout_task);
1535   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1536   GNUNET_free (th);
1537   if ((0 == message_ready_size (mesh)) && (NULL != mesh->th))
1538   {
1539     /* queue empty, no point in asking for transmission */
1540     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1541     mesh->th = NULL;
1542   }
1543 }
1544
1545
1546 void
1547 GNUNET_MESH_receive_done (struct GNUNET_MESH_Channel *channel)
1548 {
1549   send_ack (channel);
1550 }
1551
1552
1553 /**
1554  * Request information about the running mesh peer.
1555  * The callback will be called for every channel known to the service,
1556  * listing all active peers that blong to the channel.
1557  *
1558  * If called again on the same handle, it will overwrite the previous
1559  * callback and cls. To retrieve the cls, monitor_cancel must be
1560  * called first.
1561  *
1562  * WARNING: unstable API, likely to change in the future!
1563  *
1564  * @param h Handle to the mesh peer.
1565  * @param callback Function to call with the requested data.
1566  * @param callback_cls Closure for @c callback.
1567  */
1568 void
1569 GNUNET_MESH_get_channels (struct GNUNET_MESH_Handle *h,
1570                          GNUNET_MESH_ChannelsCB callback,
1571                          void *callback_cls)
1572 {
1573   struct GNUNET_MessageHeader msg;
1574
1575   msg.size = htons (sizeof (msg));
1576   msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNELS);
1577   send_packet (h, &msg, NULL);
1578   h->channels_cb = callback;
1579   h->channels_cls = callback_cls;
1580 }
1581
1582
1583 /**
1584  * Cancel a monitor request. The monitor callback will not be called.
1585  *
1586  * @param h Mesh handle.
1587  *
1588  * @return Closure given to GNUNET_MESH_monitor, if any.
1589  */
1590 void *
1591 GNUNET_MESH_get_channels_cancel (struct GNUNET_MESH_Handle *h)
1592 {
1593   void *cls;
1594
1595   cls = h->channels_cls;
1596   h->channels_cb = NULL;
1597   h->channels_cls = NULL;
1598   return cls;
1599 }
1600
1601
1602 /**
1603  * Request information about a specific channel of the running mesh peer.
1604  *
1605  * WARNING: unstable API, likely to change in the future!
1606  * FIXME Add destination option.
1607  *
1608  * @param h Handle to the mesh peer.
1609  * @param initiator ID of the owner of the channel.
1610  * @param channel_number Channel number.
1611  * @param callback Function to call with the requested data.
1612  * @param callback_cls Closure for @c callback.
1613  */
1614 void
1615 GNUNET_MESH_show_channel (struct GNUNET_MESH_Handle *h,
1616                          struct GNUNET_PeerIdentity *initiator,
1617                          unsigned int channel_number,
1618                          GNUNET_MESH_ChannelCB callback,
1619                          void *callback_cls)
1620 {
1621   struct GNUNET_MESH_LocalMonitor msg;
1622
1623   msg.header.size = htons (sizeof (msg));
1624   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_CHANNEL);
1625   msg.owner = *initiator;
1626   msg.channel_id = htonl (channel_number);
1627   msg.reserved = 0;
1628   send_packet (h, &msg.header, NULL);
1629   h->channel_cb = callback;
1630   h->channel_cls = callback_cls;
1631 }
1632
1633
1634 /**
1635  * Function called to notify a client about the connection
1636  * begin ready to queue more data.  "buf" will be
1637  * NULL and "size" zero if the connection was closed for
1638  * writing in the meantime.
1639  *
1640  * @param cls closure
1641  * @param size number of bytes available in buf
1642  * @param buf where the callee should write the message
1643  * @return number of bytes written to buf
1644  */
1645 static size_t
1646 mesh_mq_ntr (void *cls, size_t size,
1647              void *buf)
1648 {
1649   struct GNUNET_MQ_Handle *mq = cls;
1650   struct MeshMQState *state = GNUNET_MQ_impl_state (mq);
1651   const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
1652   uint16_t msize;
1653
1654   state->th = NULL;
1655   if (NULL == buf)
1656   {
1657     GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE);
1658     return 0;
1659   }
1660   msize = ntohs (msg->size);
1661   GNUNET_assert (msize <= size);
1662   memcpy (buf, msg, msize);
1663   GNUNET_MQ_impl_send_continue (mq);
1664   return msize;
1665 }
1666
1667
1668 /**
1669  * Signature of functions implementing the
1670  * sending functionality of a message queue.
1671  *
1672  * @param mq the message queue
1673  * @param msg the message to send
1674  * @param impl_state state of the implementation
1675  */
1676 static void
1677 mesh_mq_send_impl (struct GNUNET_MQ_Handle *mq,
1678                    const struct GNUNET_MessageHeader *msg, void *impl_state)
1679 {
1680   struct MeshMQState *state = impl_state;
1681
1682   GNUNET_assert (NULL == state->th);
1683   state->th =
1684       GNUNET_MESH_notify_transmit_ready (state->channel,
1685                                          /* FIXME: add option for corking */
1686                                          GNUNET_NO,
1687                                          GNUNET_TIME_UNIT_FOREVER_REL,
1688                                          ntohs (msg->size),
1689                                          mesh_mq_ntr, mq);
1690
1691 }
1692
1693
1694 /**
1695  * Signature of functions implementing the
1696  * destruction of a message queue.
1697  * Implementations must not free 'mq', but should
1698  * take care of 'impl_state'.
1699  *
1700  * @param mq the message queue to destroy
1701  * @param impl_state state of the implementation
1702  */
1703 static void
1704 mesh_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
1705 {
1706   struct MeshMQState *state = impl_state;
1707
1708   if (NULL != state->th)
1709     GNUNET_MESH_notify_transmit_ready_cancel (state->th);
1710
1711   GNUNET_free (state);
1712 }
1713
1714
1715 /**
1716  * Create a message queue for a mesh channel.
1717  * The message queue can only be used to transmit messages,
1718  * not to receive them.
1719  *
1720  * @param channel the channel to create the message qeue for
1721  * @return a message queue to messages over the channel
1722  */
1723 struct GNUNET_MQ_Handle *
1724 GNUNET_MESH_mq_create (struct GNUNET_MESH_Channel *channel)
1725 {
1726   struct GNUNET_MQ_Handle *mq;
1727   struct MeshMQState *state;
1728
1729   state = GNUNET_new (struct MeshMQState);
1730   state->channel = channel;
1731
1732   mq = GNUNET_MQ_queue_for_callbacks (mesh_mq_send_impl,
1733                                       mesh_mq_destroy_impl,
1734                                       NULL, /* FIXME: cancel impl. */
1735                                       state,
1736                                       NULL, /* no msg handlers */
1737                                       NULL, /* no err handlers */
1738                                       NULL); /* no handler cls */
1739   return mq;
1740 }
1741