reduce loop counters to more practical levels
[oweals/gnunet.git] / src / gnsrecord / gnsrecord_serialization.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 /**
22  * @file gnsrecord/gnsrecord_serialization.c
23  * @brief API to serialize and deserialize 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  * Set to 1 to check that all records are well-formed (can be converted
42  * to string) during serialization/deserialization.
43  */
44 #define DEBUG_GNSRECORDS 0
45
46 GNUNET_NETWORK_STRUCT_BEGIN
47
48
49 /**
50  * Internal format of a record in the serialized form.
51  */
52 struct NetworkRecord
53 {
54
55   /**
56    * Expiration time for the DNS record; relative or absolute depends
57    * on @e flags, network byte order.
58    */
59   uint64_t expiration_time GNUNET_PACKED;
60
61   /**
62    * Number of bytes in 'data', network byte order.
63    */
64   uint32_t data_size GNUNET_PACKED;
65
66   /**
67    * Type of the GNS/DNS record, network byte order.
68    */
69   uint32_t record_type GNUNET_PACKED;
70
71   /**
72    * Flags for the record, network byte order.
73    */
74   uint32_t flags GNUNET_PACKED;
75
76 };
77
78 GNUNET_NETWORK_STRUCT_END
79
80
81 /**
82  * Calculate how many bytes we will need to serialize the given
83  * records.
84  *
85  * @param rd_count number of records in the rd array
86  * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
87  * @return the required size to serialize, -1 on error
88  */
89 ssize_t
90 GNUNET_GNSRECORD_records_get_size (unsigned int rd_count,
91                                    const struct GNUNET_GNSRECORD_Data *rd)
92 {
93   size_t ret;
94
95   ret = sizeof (struct NetworkRecord) * rd_count;
96   for (unsigned int i=0;i<rd_count;i++)
97   {
98     if ((ret + rd[i].data_size) < ret)
99     {
100       GNUNET_break (0);
101       return -1;
102     }
103     ret += rd[i].data_size;
104 #if DEBUG_GNSRECORDS
105     {
106       char *str;
107
108       str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
109                                               rd[i].data,
110                                               rd[i].data_size);
111       if (NULL == str)
112       {
113         GNUNET_break_op (0);
114         return -1;
115       }
116       GNUNET_free (str);
117     }
118 #endif
119   }
120   if (ret > SSIZE_MAX)
121   {
122     GNUNET_break (0);
123     return -1;
124   }
125   return (ssize_t) ret;
126 }
127
128
129 /**
130  * Serialize the given records to the given destination buffer.
131  *
132  * @param rd_count number of records in the rd array
133  * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
134  * @param dest_size size of the destination array
135  * @param dest where to write the result
136  * @return the size of serialized records, -1 if records do not fit
137  */
138 ssize_t
139 GNUNET_GNSRECORD_records_serialize (unsigned int rd_count,
140                                     const struct GNUNET_GNSRECORD_Data *rd,
141                                     size_t dest_size,
142                                     char *dest)
143 {
144   struct NetworkRecord rec;
145   size_t off;
146
147   off = 0;
148   for (unsigned int i=0;i<rd_count;i++)
149   {
150     LOG (GNUNET_ERROR_TYPE_DEBUG,
151          "Serializing record %u with flags %d and expiration time %llu\n",
152          i,
153          rd[i].flags,
154          (unsigned long long) rd[i].expiration_time);
155     rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
156     rec.data_size = htonl ((uint32_t) rd[i].data_size);
157     rec.record_type = htonl (rd[i].record_type);
158     rec.flags = htonl (rd[i].flags);
159     if ( (off + sizeof (rec) > dest_size) ||
160          (off + sizeof (rec) < off) )
161     {
162       GNUNET_break (0);
163       return -1;
164     }
165     GNUNET_memcpy (&dest[off],
166                    &rec,
167                    sizeof (rec));
168     off += sizeof (rec);
169     if ( (off + rd[i].data_size > dest_size) ||
170          (off + rd[i].data_size < off) )
171     {
172       GNUNET_break (0);
173       return -1;
174     }
175     GNUNET_memcpy (&dest[off],
176                    rd[i].data,
177                    rd[i].data_size);
178     off += rd[i].data_size;
179 #if DEBUG_GNSRECORDS
180     {
181       char *str;
182
183       str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
184                                               rd[i].data,
185                                               rd[i].data_size);
186       if (NULL == str)
187       {
188         GNUNET_break_op (0);
189         return -1;
190       }
191       GNUNET_free (str);
192     }
193 #endif
194   }
195   return off;
196 }
197
198
199 /**
200  * Deserialize the given records to the given destination.
201  *
202  * @param len size of the serialized record data
203  * @param src the serialized record data
204  * @param rd_count number of records in the rd array
205  * @param dest where to put the data
206  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
207  */
208 int
209 GNUNET_GNSRECORD_records_deserialize (size_t len,
210                                       const char *src,
211                                       unsigned int rd_count,
212                                       struct GNUNET_GNSRECORD_Data *dest)
213 {
214   struct NetworkRecord rec;
215   size_t off;
216
217   off = 0;
218   for (unsigned int i=0;i<rd_count;i++)
219   {
220     if ( (off + sizeof (rec) > len) ||
221          (off + sizeof (rec) < off) )
222     {
223       GNUNET_break_op (0);
224       return GNUNET_SYSERR;
225     }
226     GNUNET_memcpy (&rec,
227                    &src[off],
228                    sizeof (rec));
229     dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
230     dest[i].data_size = ntohl ((uint32_t) rec.data_size);
231     dest[i].record_type = ntohl (rec.record_type);
232     dest[i].flags = ntohl (rec.flags);
233     off += sizeof (rec);
234     if ( (off + dest[i].data_size > len) ||
235          (off + dest[i].data_size < off) )
236     {
237       GNUNET_break_op (0);
238       return GNUNET_SYSERR;
239     }
240     dest[i].data = &src[off];
241     off += dest[i].data_size;
242 #if GNUNET_EXTRA_LOGGING
243     {
244       char *str;
245
246       str = GNUNET_GNSRECORD_value_to_string (dest[i].record_type,
247                                               dest[i].data,
248                                               dest[i].data_size);
249       if (NULL == str)
250       {
251         GNUNET_break_op (0);
252         return GNUNET_SYSERR;
253       }
254       GNUNET_free (str);
255     }
256 #endif
257     LOG (GNUNET_ERROR_TYPE_DEBUG,
258          "Deserialized record %u with flags %d and expiration time %llu\n",
259          i,
260          dest[i].flags,
261          (unsigned long long) dest[i].expiration_time);
262   }
263   return GNUNET_OK;
264 }
265
266
267 /* end of gnsrecord_serialization.c */