Fixed bad merge
[oweals/gnunet.git] / src / mesh / mesh_api_new.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_new.c
20  * @brief mesh api: client implementation of mesh service
21  * @author Bartlomiej Polot
22  *
23  * TODO:
24  * - callbacks to client missing on certain events
25  * - processing messages from service is incomplete
26  *
27  * STRUCTURE:
28  * - CONSTANTS
29  * - DATA STRUCTURES
30  * - AUXILIARY FUNCTIONS
31  * - RECEIVE HANDLERS
32  * - SEND FUNCTIONS
33  * - API CALL DEFINITIONS
34  */
35 #ifdef __cplusplus
36 extern "C"
37 {
38 #if 0                           /* keep Emacsens' auto-indent happy */
39 }
40 #endif
41 #endif
42
43 #include "platform.h"
44 #include "gnunet_common.h"
45 #include "gnunet_client_lib.h"
46 #include "gnunet_util_lib.h"
47 #include "gnunet_peer_lib.h"
48 #include "gnunet_mesh_service_new.h"
49 #include "mesh.h"
50 #include "mesh_protocol.h"
51
52
53 /******************************************************************************/
54 /************************      DATA STRUCTURES     ****************************/
55 /******************************************************************************/
56
57 /**
58  * Transmission queue to the service
59  */
60 struct GNUNET_MESH_TransmitHandle
61 {
62
63     /**
64      * Double Linked list
65      */
66   struct GNUNET_MESH_TransmitHandle *next;
67
68     /**
69      * Double Linked list
70      */
71   struct GNUNET_MESH_TransmitHandle *prev;
72
73     /**
74      * Tunnel this message is sent over (may be NULL for control messages).
75      */
76   struct GNUNET_MESH_Tunnel *tunnel;
77
78     /**
79      * Data itself, currently points to the end of this struct if
80      * we have a message already, NULL if the message is to be
81      * obtained from the callback.
82      */
83   const struct GNUNET_MessageHeader *data;
84
85     /**
86      * Callback to obtain the message to transmit, or NULL if we
87      * got the message in 'data'.  Notice that messages built
88      * by 'notify' need to be encapsulated with information about
89      * the 'target'.
90      */
91   GNUNET_CONNECTION_TransmitReadyNotify notify;
92
93     /**
94      * Closure for 'notify'
95      */
96   void *notify_cls;
97
98     /**
99      * How long is this message valid.  Once the timeout has been
100      * reached, the message must no longer be sent.  If this
101      * is a message with a 'notify' callback set, the 'notify'
102      * function should be called with 'buf' NULL and size 0.
103      */
104   struct GNUNET_TIME_Absolute timeout;
105
106     /**
107      * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
108      */
109   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
110
111     /**
112      * Priority of the message.  The queue is sorted by priority,
113      * control messages have the maximum priority (UINT32_MAX).
114      */
115   uint32_t priority;
116
117     /**
118      * Target of the message, 0 for broadcast.  This field
119      * is only valid if 'notify' is non-NULL.
120      */
121   GNUNET_PEER_Id target;
122
123     /**
124      * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
125      */
126   size_t size;
127 };
128
129
130 /**
131  * Opaque handle to the service.
132  */
133 struct GNUNET_MESH_Handle
134 {
135
136     /**
137      * Handle to the server connection, to send messages later
138      */
139   struct GNUNET_CLIENT_Connection *client;
140
141     /**
142      * Set of handlers used for processing incoming messages in the tunnels
143      */
144   const struct GNUNET_MESH_MessageHandler *message_handlers;
145
146     /**
147      * Set of applications that should be claimed to be offered at this node.
148      * Note that this is just informative, the appropiate handlers must be
149      * registered independently and the mapping is up to the developer of the
150      * client application.
151      */
152   const GNUNET_MESH_ApplicationType *applications;
153
154     /**
155      * Double linked list of the tunnels this client is connected to.
156      */
157   struct GNUNET_MESH_Tunnel *tunnels_head;
158   struct GNUNET_MESH_Tunnel *tunnels_tail;
159
160     /**
161      * Callback for inbound tunnel creation
162      */
163   GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel;
164
165     /**
166      * Callback for inbound tunnel disconnection
167      */
168   GNUNET_MESH_TunnelEndHandler *cleaner;
169
170     /**
171      * Handle to cancel pending transmissions in case of disconnection
172      */
173   struct GNUNET_CLIENT_TransmitHandle *th;
174
175     /**
176      * Closure for all the handlers given by the client
177      */
178   void *cls;
179
180     /**
181      * Messages to send to the service
182      */
183   struct GNUNET_MESH_TransmitHandle *th_head;
184   struct GNUNET_MESH_TransmitHandle *th_tail;
185
186     /**
187      * tid of the next tunnel to create (to avoid reusing IDs often)
188      */
189   MESH_TunnelNumber next_tid;
190   unsigned int n_handlers;
191   unsigned int n_applications;
192   unsigned int max_queue_size;
193
194     /**
195      * Have we started the task to receive messages from the service
196      * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message.
197      */
198   int in_receive;
199
200     /**
201      * Number of packets queued
202      */
203   unsigned int npackets;
204
205   /**
206    * Configuration given by the client, in case of reconnection
207    */
208   const struct GNUNET_CONFIGURATION_Handle *cfg;
209 };
210
211
212 /**
213  * Description of a peer
214  */
215 struct GNUNET_MESH_Peer
216 {
217     /**
218      * ID of the peer in short form
219      */
220   GNUNET_PEER_Id id;
221
222   /**
223    * Tunnel this peer belongs to
224    */
225   struct GNUNET_MESH_Tunnel *t;
226
227   /**
228    * Flag indicating whether service has informed about its connection
229    */
230   int connected;
231
232 };
233
234
235 /**
236  * Opaque handle to a tunnel.
237  */
238 struct GNUNET_MESH_Tunnel
239 {
240
241     /**
242      * DLL
243      */
244   struct GNUNET_MESH_Tunnel *next;
245   struct GNUNET_MESH_Tunnel *prev;
246
247     /**
248      * Callback to execute when peers connect to the tunnel
249      */
250   GNUNET_MESH_TunnelConnectHandler connect_handler;
251
252     /**
253      * Callback to execute when peers disconnect from the tunnel
254      */
255   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
256
257     /**
258      * Closure for the connect/disconnect handlers
259      */
260   void *cls;
261
262     /**
263      * Handle to the mesh this tunnel belongs to
264      */
265   struct GNUNET_MESH_Handle *mesh;
266
267     /**
268      * Local ID of the tunnel
269      */
270   MESH_TunnelNumber tid;
271
272     /**
273      * Owner of the tunnel
274      */
275   GNUNET_PEER_Id owner;
276
277     /**
278      * All peers added to the tunnel
279      */
280   struct GNUNET_MESH_Peer **peers;
281
282   /**
283    * List of application types that have been requested for this tunnel
284    */
285   GNUNET_MESH_ApplicationType *apps;
286
287   /**
288    * Any data the caller wants to put in here
289    */
290   void *ctx;
291
292   /**
293      * Number of peers added to the tunnel
294      */
295   unsigned int npeers;
296
297     /**
298      * Number of packets queued in this tunnel
299      */
300   unsigned int npackets;
301
302     /**
303      * Number of applications requested this tunnel
304      */
305   unsigned int napps;
306
307 };
308
309
310 /******************************************************************************/
311 /***********************     AUXILIARY FUNCTIONS      *************************/
312 /******************************************************************************/
313
314 /**
315  * Get the tunnel handler for the tunnel specified by id from the given handle
316  * @param h Mesh handle
317  * @param tid ID of the wanted tunnel
318  * @return handle to the required tunnel or NULL if not found
319  */
320 static struct GNUNET_MESH_Tunnel *
321 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
322 {
323   struct GNUNET_MESH_Tunnel *t;
324
325   t = h->tunnels_head;
326   while (t != NULL)
327   {
328     if (t->tid == tid)
329       return t;
330     t = t->next;
331   }
332   return NULL;
333 }
334
335
336 /**
337  * Create a new tunnel and insert it in the tunnel list of the mesh handle
338  * @param h Mesh handle
339  * @param tid desired tid of the tunnel, 0 to assign one automatically
340  * @return handle to the created tunnel
341  */
342 static struct GNUNET_MESH_Tunnel *
343 create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
344 {
345   struct GNUNET_MESH_Tunnel *t;
346
347   t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
348   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
349   t->mesh = h;
350   if (0 == tid)
351   {
352     t->tid = h->next_tid;
353     while (NULL != retrieve_tunnel (h, h->next_tid))
354     {
355       h->next_tid++;
356       h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
357       h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
358     }
359   }
360   else
361   {
362     t->tid = tid;
363   }
364   return t;
365 }
366
367
368 /**
369  * Get the tunnel handler for the tunnel specified by id from the given handle
370  * @param h Mesh handle
371  * @param tid ID of the wanted tunnel
372  * @return handle to the required tunnel or NULL if not found
373  */
374 static void
375 destroy_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
376 {
377   struct GNUNET_MESH_Tunnel *t;
378   struct GNUNET_PeerIdentity pi;
379   unsigned int i;
380
381   t = retrieve_tunnel (h, tid);
382   if (NULL == t)
383   {
384     GNUNET_break (0);
385     return;
386   }
387   /* TODO remove data packets from queue */
388   GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t);
389   for (i = 0; i < t->npeers; i++)
390   {
391     if (NULL != t->disconnect_handler && t->peers[i]->connected)
392     {
393       GNUNET_PEER_resolve (t->peers[i]->id, &pi);
394       t->disconnect_handler (t->cls, &pi);
395     }
396     GNUNET_PEER_change_rc (t->peers[i]->id, -1);
397     GNUNET_free (t->peers[i]);
398   }
399   if (NULL != h->cleaner && 0 != t->owner)
400     h->cleaner (h->cls, t, t->ctx);
401   if (0 != t->owner)
402     GNUNET_PEER_change_rc (t->owner, -1);
403   if (0 != t->napps && t->apps)
404     GNUNET_free (t->apps);
405   if (t->npeers > 0)
406     GNUNET_free (t->peers);
407   GNUNET_free (t);
408   return;
409 }
410
411 /**
412  * Get the peer descriptor for the peer with id from the given tunnel
413  * @param t Tunnel handle
414  * @param id Short form ID of the wanted peer
415  * @return handle to the requested peer or NULL if not found
416  */
417 static struct GNUNET_MESH_Peer *
418 retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id)
419 {
420   unsigned int i;
421
422   for (i = 0; i < t->npeers; i++)
423     if (t->peers[i]->id == id)
424       return t->peers[i];
425   return NULL;
426 }
427
428
429 /**
430  * Add a peer into a tunnel
431  * @param t Tunnel handle
432  * @param pi Full ID of the new peer
433  * @return handle to the newly created peer
434  */
435 static struct GNUNET_MESH_Peer *
436 add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t,
437                     const struct GNUNET_PeerIdentity *pi)
438 {
439   struct GNUNET_MESH_Peer *p;
440   GNUNET_PEER_Id id;
441
442   id = GNUNET_PEER_intern (pi);
443
444   p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
445   p->id = id;
446   p->t = t;
447   GNUNET_array_append (t->peers, t->npeers, p);
448   return p;
449 }
450
451
452 /**
453  * Remove a peer from a tunnel
454  * @param t Tunnel handle
455  * @param p Peer handle
456  */
457 static void
458 remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p)
459 {
460   unsigned int i;
461
462   for (i = 0; i < p->t->npeers; i++)
463   {
464     if (p->t->peers[i] == p)
465       break;
466   }
467   if (i == p->t->npeers)
468   {
469     GNUNET_break (0);
470     return;
471   }
472   p->t->peers[i] = p->t->peers[p->t->npeers - 1];
473   GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1);
474 }
475
476
477 /**
478  * Notify client that the transmission has timed out
479  * @param cls closure
480  * @param tc task context
481  */
482 static void
483 timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
484 {
485   struct GNUNET_MESH_TransmitHandle *th = cls;
486   struct GNUNET_MESH_Handle *mesh;
487
488   mesh = th->tunnel->mesh;
489   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
490   if (th->notify != NULL)
491     th->notify (th->notify_cls, 0, NULL);
492   GNUNET_free (th);
493   if ((NULL == mesh->th_head) && (NULL != mesh->th))
494   {
495     /* queue empty, no point in asking for transmission */
496     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
497     mesh->th = NULL;
498   }
499 }
500
501
502 /**
503  * Add a transmit handle to the transmission queue by priority and set the
504  * timeout if needed.
505  *
506  * @param h mesh handle with the queue head and tail
507  * @param q handle to the packet to be transmitted
508  */
509 static void
510 add_to_queue (struct GNUNET_MESH_Handle *h,
511               struct GNUNET_MESH_TransmitHandle *th)
512 {
513   struct GNUNET_MESH_TransmitHandle *p;
514
515   p = h->th_head;
516   while ((NULL != p) && (th->priority <= p->priority))
517     p = p->next;
518   if (NULL == p)
519     p = h->th_tail;
520   else
521     p = p->prev;
522   GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
523   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
524     return;
525   th->timeout_task =
526       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
527                                     (th->timeout), &timeout_transmission, th);
528 }
529
530
531 static void
532 send_packet (struct GNUNET_MESH_Handle *h,
533              const struct GNUNET_MessageHeader *msg);
534
535
536 /**
537  * Reconnect to the service, retransmit all infomation to try to restore the
538  * original state.
539  *
540  * @param h handle to the mesh
541  *
542  * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
543  */
544 static int
545 reconnect (struct GNUNET_MESH_Handle *h)
546 {
547   struct GNUNET_MESH_Tunnel *t;
548   unsigned int i;
549
550   h->in_receive = GNUNET_NO;
551   /* disconnect */
552   if (NULL != h->th)
553   {
554     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
555   }
556   if (NULL != h->client)
557   {
558     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
559   }
560
561   /* connect again */
562   h->client = GNUNET_CLIENT_connect ("mesh", h->cfg);
563   if (h->client == NULL)
564   {
565     /* FIXME: panic? exponential backoff retry? */
566     GNUNET_break (0);
567     return GNUNET_NO;
568   }
569   /* Rebuild all tunnels */
570   for (t = h->tunnels_head; NULL != t; t = t->next)
571   {
572     struct GNUNET_MESH_TunnelMessage tmsg;
573     struct GNUNET_MESH_PeerControl pmsg;
574
575     tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
576     tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
577     tmsg.tunnel_id = htonl (t->tid);
578     send_packet (h, &tmsg.header);
579
580     pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
581     pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
582     pmsg.tunnel_id = htonl (t->tid);
583
584     /* Reconnect all peers */
585     for (i = 0; i < t->npeers; i++)
586     {
587       GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer);
588       if (NULL != t->disconnect_handler && t->peers[i]->connected)
589         t->disconnect_handler (t->cls, &pmsg.peer);
590       /* If the tunnel was "by type", dont connect individual peers */
591       if (0 == t->napps)
592         send_packet (t->mesh, &pmsg.header);
593     }
594     /* Reconnect all types, if any  */
595     for (i = 0; i < t->napps; i++)
596     {
597       struct GNUNET_MESH_ConnectPeerByType msg;
598
599       msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
600       msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
601       msg.tunnel_id = htonl (t->tid);
602       msg.type = htonl (t->apps[i]);
603       send_packet (t->mesh, &msg.header);
604     }
605   }
606   return GNUNET_YES;
607 }
608
609
610 /******************************************************************************/
611 /***********************      RECEIVE HANDLERS     ****************************/
612 /******************************************************************************/
613
614 /**
615  * Process the new tunnel notification and add it to the tunnels in the handle
616  *
617  * @param h     The mesh handle
618  * @param msg   A message with the details of the new incoming tunnel
619  */
620 static void
621 process_tunnel_create (struct GNUNET_MESH_Handle *h,
622                        const struct GNUNET_MESH_TunnelMessage *msg)
623 {
624   struct GNUNET_MESH_Tunnel *t;
625   MESH_TunnelNumber tid;
626
627   tid = ntohl (msg->tunnel_id);
628   if (tid <= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI)
629   {
630     GNUNET_break (0);
631     return;
632   }
633   t = create_tunnel (h, tid);
634   t->mesh = h;
635   t->tid = tid;
636   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
637   return;
638 }
639
640
641 /**
642  * Process the tunnel destroy notification and free associated resources
643  *
644  * @param h     The mesh handle
645  * @param msg   A message with the details of the tunnel being destroyed
646  */
647 static void
648 process_tunnel_destroy (struct GNUNET_MESH_Handle *h,
649                         const struct GNUNET_MESH_TunnelMessage *msg)
650 {
651   struct GNUNET_MESH_Tunnel *t;
652   MESH_TunnelNumber tid;
653
654   tid = ntohl (msg->tunnel_id);
655   t = retrieve_tunnel (h, tid);
656
657   t->cls = h->cls;
658   t->mesh = h;
659   t->tid = tid;
660   GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t);
661   return;
662 }
663
664
665 /**
666  * Process the new peer event and notify the upper level of it
667  *
668  * @param h     The mesh handle
669  * @param msg   A message with the details of the peer event
670  */
671 static void
672 process_peer_event (struct GNUNET_MESH_Handle *h,
673                     const struct GNUNET_MESH_PeerControl *msg)
674 {
675   struct GNUNET_MESH_Tunnel *t;
676   struct GNUNET_MESH_Peer *p;
677   struct GNUNET_TRANSPORT_ATS_Information atsi;
678   GNUNET_PEER_Id id;
679   uint16_t size;
680
681   size = ntohs (msg->header.size);
682   if (size != sizeof (struct GNUNET_MESH_PeerControl))
683   {
684     GNUNET_break (0);
685     return;
686   }
687   t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
688   if (NULL == t)
689   {
690     t = create_tunnel (h, msg->tunnel_id);
691     t->owner = GNUNET_PEER_intern (&msg->peer);
692     t->npeers = 1;
693     t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *));
694     t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer));
695     t->peers[0]->t = t;
696     t->peers[0]->connected = 1;
697     t->peers[0]->id = t->owner;
698     return;
699   }
700   id = GNUNET_PEER_search (&msg->peer);
701   if ((p = retrieve_peer (t, id)) == NULL)
702     p = add_peer_to_tunnel (t, &msg->peer);
703   atsi.type = 0;
704   atsi.value = 0;
705   if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == msg->header.type)
706   {
707     if (NULL != t->connect_handler)
708     {
709       t->connect_handler (t->cls, &msg->peer, &atsi);
710     }
711     p->connected = 1;
712   }
713   else
714   {
715     if (NULL != t->disconnect_handler && p->connected)
716     {
717       t->disconnect_handler (t->cls, &msg->peer);
718     }
719     remove_peer_from_tunnel (p);
720     GNUNET_free (p);
721   }
722 }
723
724
725 /**
726  * Process the incoming data packets
727  *
728  * @param h     The mesh handle
729  * @param msh   A message encapsulating the data
730  */
731 static void
732 process_incoming_data (struct GNUNET_MESH_Handle *h,
733                        const struct GNUNET_MessageHeader *message)
734 {
735   const struct GNUNET_MessageHeader *payload;
736   const struct GNUNET_MESH_MessageHandler *handler;
737   const struct GNUNET_PeerIdentity *peer;
738   struct GNUNET_MESH_Unicast *ucast;
739   struct GNUNET_MESH_Multicast *mcast;
740   struct GNUNET_MESH_ToOrigin *to_orig;
741   struct GNUNET_MESH_Tunnel *t;
742   uint16_t type;
743   int i;
744
745   type = ntohs (message->type);
746   switch (type)
747   {
748   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
749     ucast = (struct GNUNET_MESH_Unicast *) message;
750     t = retrieve_tunnel (h, ntohl (ucast->tid));
751     payload = (struct GNUNET_MessageHeader *) &ucast[1];
752     peer = &ucast->oid;
753     break;
754   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
755     mcast = (struct GNUNET_MESH_Multicast *) message;
756     t = retrieve_tunnel (h, ntohl (mcast->tid));
757     payload = (struct GNUNET_MessageHeader *) &mcast[1];
758     peer = &mcast->oid;
759     break;
760   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
761     to_orig = (struct GNUNET_MESH_ToOrigin *) message;
762     t = retrieve_tunnel (h, ntohl (to_orig->tid));
763     payload = (struct GNUNET_MessageHeader *) &to_orig[1];
764     peer = &to_orig->sender;
765     break;
766   default:
767     GNUNET_break (0);
768     return;
769   }
770   if (NULL == t)
771   {
772     GNUNET_break (0);
773     return;
774   }
775   for (i = 0; i < h->n_handlers; i++)
776   {
777     handler = &h->message_handlers[i];
778     if (handler->type == type)
779     {
780       struct GNUNET_TRANSPORT_ATS_Information atsi;
781
782       atsi.type = 0;
783       atsi.value = 0;
784       if (GNUNET_OK ==
785           handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi))
786       {
787         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
788                     "MESH: callback completed successfully\n");
789       }
790       else
791       {
792         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793                     "MESH: callback caused disconnection\n");
794         GNUNET_MESH_disconnect (h);
795       }
796     }
797   }
798 }
799
800
801 /**
802  * Function to process all messages received from the service
803  *
804  * @param cls closure
805  * @param msg message received, NULL on timeout or fatal error
806  */
807 static void
808 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
809 {
810   struct GNUNET_MESH_Handle *h = cls;
811
812   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: received a message from MESH\n");
813   if (msg == NULL)
814   {
815     reconnect (h);
816     return;
817   }
818   switch (ntohs (msg->type))
819   {
820     /* Notify of a new incoming tunnel */
821   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
822     process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
823     break;
824     /* Notify of a tunnel disconnection */
825   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY:
826     process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg);
827     break;
828     /* Notify of a new peer or a peer disconnect in the tunnel */
829   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD:
830   case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL:
831     process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
832     break;
833     /* Notify of a new data packet in the tunnel */
834   case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
835   case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
836   case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
837     process_incoming_data (h, msg);
838     break;
839     /* We shouldn't get any other packages, log and ignore */
840   default:
841     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
842                 "MESH: unsolicited message form service (type %d)\n",
843                 ntohs (msg->type));
844   }
845   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: message processed\n");
846   GNUNET_CLIENT_receive (h->client, &msg_received, h,
847                          GNUNET_TIME_UNIT_FOREVER_REL);
848 }
849
850
851 /******************************************************************************/
852 /************************       SEND FUNCTIONS     ****************************/
853 /******************************************************************************/
854
855 /**
856  * Function called to send a message to the service.
857  * "buf" will be NULL and "size" zero if the socket was closed for writing in
858  * the meantime.
859  *
860  * @param cls closure, the mesh handle
861  * @param size number of bytes available in buf
862  * @param buf where the callee should write the connect message
863  * @return number of bytes written to buf
864  */
865 static size_t
866 send_callback (void *cls, size_t size, void *buf)
867 {
868   struct GNUNET_MESH_Handle *h = cls;
869   struct GNUNET_MESH_TransmitHandle *th;
870   char *cbuf = buf;
871   size_t tsize;
872   size_t psize;
873
874   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
875   h->th = NULL;
876   if ((0 == size) || (NULL == buf))
877   {
878     reconnect (h);
879     return 0;
880   }
881   tsize = 0;
882   while ((NULL != (th = h->th_head)) && (size >= th->size))
883   {
884     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     type: %u\n",
885                 ntohs (th->data->type));
886     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:     size: %u\n",
887                 ntohs (th->data->size));
888     if (NULL == th->data)
889     {
890       GNUNET_assert (NULL != th->notify);
891       if (th->target == 0)
892       {
893         /* multicast */
894         struct GNUNET_MESH_Multicast mc;
895
896         GNUNET_assert (size >= sizeof (mc) + th->size);
897         psize =
898             th->notify (th->notify_cls, size - sizeof (mc), &cbuf[sizeof (mc)]);
899         if (psize > 0)
900         {
901           mc.header.size = htons (sizeof (mc) + th->size);
902           mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
903           mc.tid = htonl (th->tunnel->tid);
904           memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
905           memcpy (cbuf, &mc, sizeof (mc));
906           psize = th->size + sizeof (mc);
907         }
908       }
909       else
910       {
911         /* unicast */
912         struct GNUNET_MESH_Unicast uc;
913
914         GNUNET_assert (size >= sizeof (uc) + th->size);
915         psize =
916             th->notify (th->notify_cls, size - sizeof (uc), &cbuf[sizeof (uc)]);
917         if (psize > 0)
918         {
919           uc.header.size = htons (sizeof (uc) + th->size);
920           uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
921           uc.tid = htonl (th->tunnel->tid);
922           memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));     /* myself */
923           GNUNET_PEER_resolve (th->target, &uc.destination);
924           memcpy (cbuf, &uc, sizeof (uc));
925           psize = th->size + sizeof (uc);
926         }
927       }
928     }
929     else
930     {
931       memcpy (cbuf, th->data, th->size);
932       psize = th->size;
933     }
934     if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
935       GNUNET_SCHEDULER_cancel (th->timeout_task);
936     GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
937     GNUNET_free (th);
938     cbuf += psize;
939     size -= psize;
940     tsize += psize;
941   }
942   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   total size: %u\n", tsize);
943   if (NULL != (th = h->th_head))
944   {
945     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh:   next size: %u\n", th->size);
946     h->th =
947         GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
948                                              GNUNET_TIME_UNIT_FOREVER_REL,
949                                              GNUNET_YES, &send_callback, h);
950   }
951   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
952   if (GNUNET_NO == h->in_receive)
953   {
954     h->in_receive = GNUNET_YES;
955     GNUNET_CLIENT_receive (h->client, &msg_received, h,
956                            GNUNET_TIME_UNIT_FOREVER_REL);
957   }
958   return tsize;
959 }
960
961
962 /**
963  * Auxiliary function to send an already constructed packet to the service.
964  * Takes care of creating a new queue element, copying the message and
965  * calling the tmt_rdy function if necessary.
966  * @param h mesh handle
967  * @param msg message to transmit
968  */
969 static void
970 send_packet (struct GNUNET_MESH_Handle *h,
971              const struct GNUNET_MessageHeader *msg)
972 {
973   struct GNUNET_MESH_TransmitHandle *th;
974   size_t msize;
975
976   msize = ntohs (msg->size);
977   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize);
978   th->priority = UINT32_MAX;
979   th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
980   th->size = msize;
981   th->data = (void *) &th[1];
982   memcpy (&th[1], msg, msize);
983   add_to_queue (h, th);
984   if (NULL != h->th)
985     return;
986   h->th =
987       GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
988                                            GNUNET_TIME_UNIT_FOREVER_REL,
989                                            GNUNET_YES, &send_callback, h);
990 }
991
992
993 /******************************************************************************/
994 /**********************      API CALL DEFINITIONS     *************************/
995 /******************************************************************************/
996
997 /**
998  * Connect to the mesh service.
999  *
1000  * @param cfg configuration to use
1001  * @param queue_size size of the data message queue, shared among all tunnels
1002  *                   (each tunnel is guaranteed to accept at least one message,
1003  *                    no matter what is the status of other tunnels)
1004  * @param cls closure for the various callbacks that follow
1005  *            (including handlers in the handlers array)
1006  * @param new_tunnel function called when an *inbound* tunnel is created
1007  * @param cleaner function called when an *inbound* tunnel is destroyed
1008  * @param handlers callbacks for messages we care about, NULL-terminated
1009  *                note that the mesh is allowed to drop notifications about
1010  *                inbound messages if the client does not process them fast
1011  *                enough (for this notification type, a bounded queue is used)
1012  * @param stypes list of the applications that this client claims to provide
1013  * @return handle to the mesh service NULL on error
1014  *         (in this case, init is never called)
1015  */
1016 struct GNUNET_MESH_Handle *
1017 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1018                      unsigned int queue_size, void *cls,
1019                      GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
1020                      GNUNET_MESH_TunnelEndHandler cleaner,
1021                      const struct GNUNET_MESH_MessageHandler *handlers,
1022                      const GNUNET_MESH_ApplicationType *stypes)
1023 {
1024   struct GNUNET_MESH_Handle *h;
1025   struct GNUNET_MESH_ClientConnect *msg;
1026   GNUNET_MESH_ApplicationType *apps;
1027   uint16_t napps;
1028   uint16_t *types;
1029   uint16_t ntypes;
1030   size_t size;
1031
1032   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect()\n");
1033   h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
1034   h->cfg = cfg;
1035   h->max_queue_size = queue_size;
1036   h->new_tunnel = new_tunnel;
1037   h->cleaner = cleaner;
1038   h->client = GNUNET_CLIENT_connect ("mesh", cfg);
1039   if (h->client == NULL)
1040   {
1041     GNUNET_break (0);
1042     GNUNET_free (h);
1043     return NULL;
1044   }
1045   h->cls = cls;
1046   h->message_handlers = handlers;
1047   h->applications = stypes;
1048   h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI;
1049
1050   /* count handlers and apps, calculate size */
1051   for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
1052   for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
1053   size = sizeof (struct GNUNET_MESH_ClientConnect);
1054   size += h->n_handlers * sizeof (uint16_t);
1055   size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
1056
1057   {
1058     char buf[size];
1059
1060     /* build connection packet */
1061     msg = (struct GNUNET_MESH_ClientConnect *) buf;
1062     msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
1063     msg->header.size = htons (size);
1064     types = (uint16_t *) & msg[1];
1065     for (ntypes = 0; ntypes < h->n_handlers; ntypes++)
1066       types[ntypes] = h->message_handlers[ntypes].type;
1067     apps = (GNUNET_MESH_ApplicationType *) &types[ntypes];
1068     for (napps = 0; napps < h->n_applications; napps++)
1069       apps[napps] = h->applications[napps];
1070     msg->applications = htons (napps);
1071     msg->types = htons (ntypes);
1072     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073                 "mesh: Sending %lu bytes long message %d types and %d apps\n",
1074                 ntohs (msg->header.size), ntypes, napps);
1075     send_packet (h, &msg->header);
1076   }
1077   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: GNUNET_MESH_connect() END\n");
1078   return h;
1079 }
1080
1081
1082 /**
1083  * Disconnect from the mesh service.
1084  *
1085  * @param handle connection to mesh to disconnect
1086  */
1087 void
1088 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
1089 {
1090   struct GNUNET_MESH_Tunnel *t;
1091
1092   for (t = handle->tunnels_head; NULL != t; t = t->next)
1093   {
1094     destroy_tunnel (handle, t->tid);
1095   }
1096   if (NULL != handle->th)
1097   {
1098     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
1099   }
1100   if (NULL != handle->client)
1101   {
1102     GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
1103   }
1104   GNUNET_free (handle);
1105 }
1106
1107
1108 /**
1109  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
1110  * and to broadcast).
1111  *
1112  * @param h mesh handle
1113  * @param tunnel_ctx client's tunnel context to associate with the tunnel
1114  * @param connect_handler function to call when peers are actually connected
1115  * @param disconnect_handler function to call when peers are disconnected
1116  * @param handler_cls closure for connect/disconnect handlers
1117  */
1118 struct GNUNET_MESH_Tunnel *
1119 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx,
1120                            GNUNET_MESH_TunnelConnectHandler connect_handler,
1121                            GNUNET_MESH_TunnelDisconnectHandler
1122                            disconnect_handler, void *handler_cls)
1123 {
1124   struct GNUNET_MESH_Tunnel *t;
1125   struct GNUNET_MESH_TunnelMessage msg;
1126
1127   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Creating new tunnel\n");
1128   t = create_tunnel (h, 0);
1129   t->connect_handler = connect_handler;
1130   t->disconnect_handler = disconnect_handler;
1131   t->cls = handler_cls;
1132   t->ctx = tunnel_ctx;
1133   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
1134   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1135   msg.tunnel_id = htonl (t->tid);
1136   send_packet (h, &msg.header);
1137   return t;
1138 }
1139
1140
1141 /**
1142  * Destroy an existing tunnel.
1143  *
1144  * @param tun tunnel handle
1145  */
1146 void
1147 GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tun)
1148 {
1149   struct GNUNET_MESH_Handle *h;
1150   struct GNUNET_MESH_TunnelMessage msg;
1151
1152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: Destroying tunnel\n");
1153   h = tun->mesh;
1154
1155   if (0 != tun->owner)
1156     GNUNET_PEER_change_rc (tun->owner, -1);
1157
1158   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
1159   msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
1160   msg.tunnel_id = htonl (tun->tid);
1161   destroy_tunnel (h, tun->tid);
1162   send_packet (h, &msg.header);
1163 }
1164
1165
1166 /**
1167  * Request that a peer should be added to the tunnel.  The existing
1168  * connect handler will be called ONCE with either success or failure.
1169  * This function should NOT be called again with the same peer before the
1170  * connect handler is called.
1171  *
1172  * @param tunnel handle to existing tunnel
1173  * @param timeout how long to try to establish a connection
1174  * @param peer peer to add
1175  */
1176 void
1177 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
1178                                       const struct GNUNET_PeerIdentity *peer)
1179 {
1180   struct GNUNET_MESH_PeerControl msg;
1181   GNUNET_PEER_Id peer_id;
1182   unsigned int i;
1183
1184   peer_id = GNUNET_PEER_intern (peer);
1185   for (i = 0; i < tunnel->npeers; i++)
1186   {
1187     if (tunnel->peers[i]->id == peer_id)
1188     {
1189       GNUNET_PEER_change_rc (peer_id, -1);
1190       GNUNET_break (0);
1191       return;
1192     }
1193   }
1194   add_peer_to_tunnel (tunnel, peer);
1195
1196   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1197   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
1198   msg.tunnel_id = htonl (tunnel->tid);
1199   msg.peer = *peer;
1200   send_packet (tunnel->mesh, &msg.header);
1201
1202   return;
1203 }
1204
1205
1206 /**
1207  * Request that a peer should be removed from the tunnel.  The existing
1208  * disconnect handler will be called ONCE if we were connected.
1209  *
1210  * @param tunnel handle to existing tunnel
1211  * @param peer peer to remove
1212  */
1213 void
1214 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
1215                                       const struct GNUNET_PeerIdentity *peer)
1216 {
1217   struct GNUNET_MESH_PeerControl msg;
1218   GNUNET_PEER_Id peer_id;
1219   unsigned int i;
1220
1221   peer_id = GNUNET_PEER_search (peer);
1222   if (0 == peer_id)
1223   {
1224     GNUNET_break (0);
1225     return;
1226   }
1227   for (i = 0; i < tunnel->npeers; i++)
1228     if (tunnel->peers[i]->id == peer_id)
1229       break;
1230   if (i == tunnel->npeers)
1231   {
1232     GNUNET_break (0);
1233     return;
1234   }
1235   if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1)
1236     tunnel->disconnect_handler (tunnel->cls, peer);
1237   GNUNET_PEER_change_rc (peer_id, -1);
1238   GNUNET_free (tunnel->peers[i]);
1239   tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1];
1240   GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1);
1241
1242   msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
1243   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1244   msg.tunnel_id = htonl (tunnel->tid);
1245   memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1246   send_packet (tunnel->mesh, &msg.header);
1247 }
1248
1249
1250 /**
1251  * Request that the mesh should try to connect to a peer supporting the given
1252  * message type.
1253  *
1254  * @param tunnel handle to existing tunnel
1255  * @param app_type application type that must be supported by the peer (MESH
1256  *                 should discover peer in proximity handling this type)
1257  */
1258 void
1259 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
1260                                           GNUNET_MESH_ApplicationType app_type)
1261 {
1262   struct GNUNET_MESH_ConnectPeerByType msg;
1263
1264   GNUNET_array_append (tunnel->apps, tunnel->napps, app_type);
1265
1266   msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType));
1267   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE);
1268   msg.tunnel_id = htonl (tunnel->tid);
1269   msg.type = htonl (app_type);
1270   send_packet (tunnel->mesh, &msg.header);
1271 }
1272
1273
1274 /**
1275  * Ask the mesh to call "notify" once it is ready to transmit the
1276  * given number of bytes to the specified "target".  If we are not yet
1277  * connected to the specified peer, a call to this function will cause
1278  * us to try to establish a connection.
1279  *
1280  * @param tunnel tunnel to use for transmission
1281  * @param cork is corking allowed for this transmission?
1282  * @param priority how important is the message?
1283  * @param maxdelay how long can the message wait?
1284  * @param target destination for the message,
1285  *               NULL for multicast to all tunnel targets
1286  * @param notify_size how many bytes of buffer space does notify want?
1287  * @param notify function to call when buffer space is available;
1288  *        will be called with NULL on timeout or if the overall queue
1289  *        for this peer is larger than queue_size and this is currently
1290  *        the message with the lowest priority
1291  * @param notify_cls closure for notify
1292  * @return non-NULL if the notify callback was queued,
1293  *         NULL if we can not even queue the request (insufficient
1294  *         memory); if NULL is returned, "notify" will NOT be called.
1295  */
1296 struct GNUNET_MESH_TransmitHandle *
1297 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork,
1298                                    uint32_t priority,
1299                                    struct GNUNET_TIME_Relative maxdelay,
1300                                    const struct GNUNET_PeerIdentity *target,
1301                                    size_t notify_size,
1302                                    GNUNET_CONNECTION_TransmitReadyNotify notify,
1303                                    void *notify_cls)
1304 {
1305   struct GNUNET_MESH_TransmitHandle *th;
1306   size_t overhead;
1307
1308   if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size &&
1309       tunnel->npackets > 0)
1310     return NULL;                /* queue full */
1311   tunnel->npackets++;
1312   tunnel->mesh->npackets++;
1313   th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
1314   th->tunnel = tunnel;
1315   th->priority = priority;
1316   th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
1317   th->target = GNUNET_PEER_intern (target);
1318   overhead =
1319       (NULL ==
1320        target) ? sizeof (struct GNUNET_MESH_Multicast) : sizeof (struct
1321                                                                  GNUNET_MESH_Unicast);
1322   th->size = notify_size + overhead;
1323   th->notify = notify;
1324   th->notify_cls = notify_cls;
1325   add_to_queue (tunnel->mesh, th);
1326   return th;
1327 }
1328
1329
1330 /**
1331  * Cancel the specified transmission-ready notification.
1332  *
1333  * @param th handle that was returned by "notify_transmit_ready".
1334  */
1335 void
1336 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th)
1337 {
1338   struct GNUNET_MESH_Handle *mesh;
1339
1340   mesh = th->tunnel->mesh;
1341   if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1342     GNUNET_SCHEDULER_cancel (th->timeout_task);
1343   GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th);
1344   GNUNET_free (th);
1345   if ((NULL == mesh->th_head) && (NULL != mesh->th))
1346   {
1347     /* queue empty, no point in asking for transmission */
1348     GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th);
1349     mesh->th = NULL;
1350   }
1351 }
1352
1353
1354 #if 0                           /* keep Emacsens' auto-indent happy */
1355 {
1356 #endif
1357 #ifdef __cplusplus
1358 }
1359 #endif