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