- Add reverse resolution with limited functionality
[oweals/gnunet.git] / src / gns / gnunet-service-gns_reverser.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file gns/gnunet-service-gns_reverser.c
22  * @brief GNUnet GNS service
23  * @author Martin Schanzenbach
24  */
25
26
27 #include "platform.h"
28 #include "gnunet_gns_service.h"
29 #include "gnunet-service-gns_resolver.h"
30 #include "gnunet-service-gns_reverser.h"
31
32 struct ReverseTreeNode
33 {
34   /**
35    * DLL
36    */
37   struct ReverseTreeNode *next;
38
39   /**
40    * DLL
41    */
42   struct ReverseTreeNode *prev;
43
44   /**
45    * Resolved name until now
46    */
47   char *name;
48
49   /**
50    * Depth of the resolution at this node
51    */
52   uint8_t depth;
53
54   /**
55    * The pkey of the namespace
56    */
57   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
58
59 };
60
61
62 struct GNS_ReverserHandle
63 {
64   /**
65    * GNS resolver handle
66    */
67   struct GNS_ResolverHandle *rh;
68
69   /**
70    * The authority to look for
71    */
72   struct GNUNET_CRYPTO_EcdsaPublicKey authority;
73   
74   /**
75    * Resolution candidate queue
76    */
77   struct ReverseTreeNode *node_queue_head;
78
79   /**
80    * Resolution candidate queue
81    */
82   struct ReverseTreeNode *node_queue_tail;
83
84   /**
85    * Max depth for the resolution
86    */
87   uint8_t max_depth;
88
89   /**
90    * Result callback
91    */
92   GNS_ReverseResultProcessor proc;
93
94   /**
95    * Callback closure
96    */
97   void *proc_cls;
98 };
99
100 void
101 cleanup_handle (struct GNS_ReverserHandle *rh)
102 {
103   struct ReverseTreeNode *rtn;
104
105   for (rtn = rh->node_queue_head; NULL != rtn; rtn = rh->node_queue_head)
106   {
107     if (NULL != rtn->name)
108       GNUNET_free (rtn->name);
109     GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
110                                  rh->node_queue_tail,
111                                  rtn);
112     GNUNET_free (rtn);
113   }
114 }
115
116 void
117 handle_gns_result (void *cls,
118                    uint32_t rd_count,
119                    const struct GNUNET_GNSRECORD_Data *rd)
120 {
121   struct GNS_ReverserHandle *rh = cls;
122   const struct GNUNET_GNSRECORD_ReverseRecord *rr;
123   struct ReverseTreeNode *rtn;
124   char *result;
125   const char *name;
126   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127               "Got result (%d)\n", rd_count);
128
129   for (int i = 0; i < rd_count; i++)
130   {
131     /**
132      * Check if we are in the delegation set
133      */
134     if (GNUNET_GNSRECORD_TYPE_REVERSE != rd[i].record_type)
135       continue;
136     rr = rd[i].data;
137     name = (const char*) &rr[1];
138     if (0 == memcmp (&rh->authority,
139                      &rr->pkey,
140                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
141     {
142       //Found!
143       GNUNET_asprintf (&result,
144                        "%s.%s.gnu",
145                        rh->node_queue_head->name,
146                        name);
147       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148                   "Found path from %s\n", result);
149
150       rh->proc (rh->proc_cls, result);
151       cleanup_handle (rh);
152       GNUNET_free (result);
153       return;
154     } else {
155       if (rh->node_queue_head->depth >= rh->max_depth)
156         break;
157       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158                   "Found REVERSE from %s\n", name);
159
160       rtn = GNUNET_new (struct ReverseTreeNode);
161       if (NULL == rh->node_queue_head->name)
162         rtn->name = GNUNET_strdup (name);
163       else
164         GNUNET_asprintf (&rtn->name,
165                          "%s.%s",
166                          rh->node_queue_head->name,
167                          name);
168       rtn->depth = rh->node_queue_head->depth + 1;
169       rtn->pkey = rr->pkey;
170       GNUNET_CONTAINER_DLL_insert_tail (rh->node_queue_head,
171                                         rh->node_queue_tail,
172                                         rtn);
173     }
174   }
175
176   /**
177    * Done here remove node from queue
178    */
179   rtn = rh->node_queue_head;
180   GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
181                                rh->node_queue_tail,
182                                rtn);
183   if (NULL == rh->node_queue_head)
184   {
185     //No luck
186     rh->proc (rh->proc_cls, NULL);
187     cleanup_handle (rh);
188     return;
189   }
190   rh->rh = GNS_resolver_lookup (&rh->node_queue_head->pkey,
191                                 GNUNET_GNSRECORD_TYPE_REVERSE,
192                                 "+.gnu",
193                                 NULL,
194                                 GNUNET_GNS_LO_DEFAULT,
195                                 &handle_gns_result,
196                                 rh);
197 }
198
199 struct GNS_ReverserHandle *
200 GNS_reverse_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *target,
201                     const struct GNUNET_CRYPTO_EcdsaPublicKey *authority,
202                     GNS_ReverseResultProcessor proc,
203                     void *proc_cls)
204 {
205   struct GNS_ReverserHandle *rh;
206   struct ReverseTreeNode *rtn;
207
208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
209               "Starting reverse resolution\n");
210   rh = GNUNET_new (struct GNS_ReverserHandle);
211   rh->proc = proc;
212   rh->proc_cls = proc_cls;
213   rtn = GNUNET_new (struct ReverseTreeNode);
214   rtn->name = NULL;
215   rtn->pkey = *target;
216   rtn->depth = 0;
217   GNUNET_CONTAINER_DLL_insert (rh->node_queue_head,
218                                rh->node_queue_tail,
219                                rtn);
220   rh->authority = *authority;
221   rh->max_depth = 3; //TODO make argument
222   rh->rh = GNS_resolver_lookup (target,
223                                 GNUNET_GNSRECORD_TYPE_REVERSE,
224                                 "+.gnu",
225                                 NULL,
226                                 GNUNET_GNS_LO_DEFAULT,
227                                 &handle_gns_result,
228                                 rh);
229   return rh;
230 }
231
232 /**
233  * Cancel active resolution (i.e. client disconnected).
234  *
235  * @param rh resolution to abort
236  */
237 void
238 GNS_reverse_lookup_cancel (struct GNS_ReverserHandle *rh)
239 {
240   cleanup_handle (rh);
241   return;
242 }
243
244