paragraph for gnunet devs that don't know how to use the web
[oweals/gnunet.git] / src / gnsrecord / gnsrecord_misc.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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file gnsrecord/gnsrecord_misc.c
21  * @brief MISC functions related to GNS records
22  * @author Martin Schanzenbach
23  * @author Matthias Wachs
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_signatures.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_dnsparser_lib.h"
33 #include "gnunet_tun_lib.h"
34
35
36 #define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
37
38 /**
39  * Convert a UTF-8 string to UTF-8 lowercase
40  * @param src source string
41  * @return converted result
42  */
43 char *
44 GNUNET_GNSRECORD_string_to_lowercase (const char *src)
45 {
46   char *res;
47
48   res = GNUNET_strdup (src);
49   GNUNET_STRINGS_utf8_tolower (src, res);
50   return res;
51 }
52
53
54 /**
55  * Convert a zone key to a string (for printing debug messages).
56  * This is one of the very few calls in the entire API that is
57  * NOT reentrant!
58  *
59  * @param z the zone key
60  * @return string form; will be overwritten by next call to #GNUNET_GNSRECORD_z2s
61  */
62 const char *
63 GNUNET_GNSRECORD_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z)
64 {
65   static char buf[sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) * 8];
66   char *end;
67
68   end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
69                                        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
70                                        buf, sizeof (buf));
71   if (NULL == end)
72   {
73     GNUNET_break (0);
74     return NULL;
75   }
76   *end = '\0';
77   return buf;
78 }
79
80
81 /**
82  * Compares if two records are equal (ignoring flags such
83  * as authority, private and pending, but not relative vs.
84  * absolute expiration time).
85  *
86  * @param a record
87  * @param b record
88  * @return #GNUNET_YES if the records are equal or #GNUNET_NO if they are not
89  */
90 int
91 GNUNET_GNSRECORD_records_cmp (const struct GNUNET_GNSRECORD_Data *a,
92                               const struct GNUNET_GNSRECORD_Data *b)
93 {
94   LOG (GNUNET_ERROR_TYPE_DEBUG,
95        "Comparing records\n");
96   if (a->record_type != b->record_type)
97   {
98     LOG (GNUNET_ERROR_TYPE_DEBUG,
99          "Record type %lu != %lu\n", a->record_type, b->record_type);
100     return GNUNET_NO;
101   }
102   if ((a->expiration_time != b->expiration_time) &&
103       ((a->expiration_time != 0) && (b->expiration_time != 0)))
104   {
105     LOG (GNUNET_ERROR_TYPE_DEBUG,
106          "Expiration time %llu != %llu\n",
107          a->expiration_time,
108          b->expiration_time);
109     return GNUNET_NO;
110   }
111   if ((a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS)
112        != (b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS))
113   {
114     LOG (GNUNET_ERROR_TYPE_DEBUG,
115          "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
116          a->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS, b->flags,
117          b->flags & GNUNET_GNSRECORD_RF_RCMP_FLAGS);
118     return GNUNET_NO;
119   }
120   if (a->data_size != b->data_size)
121   {
122     LOG (GNUNET_ERROR_TYPE_DEBUG,
123          "Data size %lu != %lu\n",
124          a->data_size,
125          b->data_size);
126     return GNUNET_NO;
127   }
128   if (0 != memcmp (a->data, b->data, a->data_size))
129   {
130     LOG (GNUNET_ERROR_TYPE_DEBUG,
131          "Data contents do not match\n");
132     return GNUNET_NO;
133   }
134   LOG (GNUNET_ERROR_TYPE_DEBUG,
135        "Records are equal\n");
136   return GNUNET_YES;
137 }
138
139
140 /**
141  * Returns the expiration time of the given block of records. The block
142  * expiration time is the expiration time of the record with smallest
143  * expiration time.
144  *
145  * @param rd_count number of records given in @a rd
146  * @param rd array of records
147  * @return absolute expiration time
148  */
149 struct GNUNET_TIME_Absolute
150 GNUNET_GNSRECORD_record_get_expiration_time (unsigned int rd_count,
151                                              const struct GNUNET_GNSRECORD_Data *rd)
152 {
153   struct GNUNET_TIME_Absolute expire;
154   struct GNUNET_TIME_Absolute at;
155   struct GNUNET_TIME_Relative rt;
156   struct GNUNET_TIME_Absolute at_shadow;
157   struct GNUNET_TIME_Relative rt_shadow;
158
159   if (NULL == rd)
160     return GNUNET_TIME_UNIT_ZERO_ABS;
161   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
162   for (unsigned int c = 0; c < rd_count; c++)
163   {
164     if (0 != (rd[c].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
165     {
166       rt.rel_value_us = rd[c].expiration_time;
167       at = GNUNET_TIME_relative_to_absolute (rt);
168     }
169     else
170     {
171       at.abs_value_us = rd[c].expiration_time;
172     }
173
174     for (unsigned int c2 = 0; c2 < rd_count; c2++)
175     {
176       /* Check for shadow record */
177       if ( (c == c2) ||
178            (rd[c].record_type != rd[c2].record_type) ||
179            (0 == (rd[c2].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) )
180           continue;
181       /* We have a shadow record */
182       if (0 != (rd[c2].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
183       {
184         rt_shadow.rel_value_us = rd[c2].expiration_time;
185         at_shadow = GNUNET_TIME_relative_to_absolute (rt_shadow);
186       }
187       else
188       {
189         at_shadow.abs_value_us = rd[c2].expiration_time;
190       }
191       at = GNUNET_TIME_absolute_max (at,
192                                      at_shadow);
193     }
194     expire = GNUNET_TIME_absolute_min (at, 
195                                        expire);
196   }
197   LOG (GNUNET_ERROR_TYPE_DEBUG,
198        "Determined expiration time for block with %u records to be %s\n",
199        rd_count,
200        GNUNET_STRINGS_absolute_time_to_string (expire));
201   return expire;
202 }
203
204
205 /**
206  * Test if a given record is expired.
207  *
208  * @return #GNUNET_YES if the record is expired,
209  *         #GNUNET_NO if not
210  */
211 int
212 GNUNET_GNSRECORD_is_expired (const struct GNUNET_GNSRECORD_Data *rd)
213 {
214   struct GNUNET_TIME_Absolute at;
215
216   if (0 != (rd->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
217     return GNUNET_NO;
218   at.abs_value_us = rd->expiration_time;
219   return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ? GNUNET_YES : GNUNET_NO;
220 }
221
222
223 /**
224  * Convert public key to the respective absolute domain name in the
225  * ".zkey" pTLD.
226  * This is one of the very few calls in the entire API that is
227  * NOT reentrant!
228  *
229  * @param pkey a public key with a point on the eliptic curve
230  * @return string "X.zkey" where X is the public
231  *         key in an encoding suitable for DNS labels.
232  */
233 const char *
234 GNUNET_GNSRECORD_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
235 {
236   static char ret[128];
237   char *pkeys;
238
239   pkeys = GNUNET_CRYPTO_ecdsa_public_key_to_string (pkey);
240   GNUNET_snprintf (ret,
241                    sizeof (ret),
242                    "%s",
243                    pkeys);
244   GNUNET_free (pkeys);
245   return ret;
246 }
247
248
249 /**
250  * Convert an absolute domain name to the
251  * respective public key.
252  *
253  * @param zkey string encoding the coordinates of the public
254  *         key in an encoding suitable for DNS labels.
255  * @param pkey set to a public key on the eliptic curve
256  * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
257  */
258 int
259 GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
260                                struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
261 {
262   if (GNUNET_OK !=
263       GNUNET_CRYPTO_ecdsa_public_key_from_string (zkey,
264                                                   strlen (zkey),
265                                                   pkey))
266     return GNUNET_SYSERR;
267   return GNUNET_OK;
268 }
269
270
271 /* end of gnsrecord_misc.c */