uncrustify as demanded.
[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 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      SPDX-License-Identifier: AGPL3.0-or-later
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    * Expiration time for the DNS record; relative or absolute depends
55    * on @e flags, network byte order.
56    */
57   uint64_t expiration_time GNUNET_PACKED;
58
59   /**
60    * Number of bytes in 'data', network byte order.
61    */
62   uint32_t data_size GNUNET_PACKED;
63
64   /**
65    * Type of the GNS/DNS record, network byte order.
66    */
67   uint32_t record_type GNUNET_PACKED;
68
69   /**
70    * Flags for the record, network byte order.
71    */
72   uint32_t flags GNUNET_PACKED;
73 };
74
75 GNUNET_NETWORK_STRUCT_END
76
77
78 /**
79  * Calculate how many bytes we will need to serialize the given
80  * records.
81  *
82  * @param rd_count number of records in the rd array
83  * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
84  * @return the required size to serialize, -1 on error
85  */
86 ssize_t
87 GNUNET_GNSRECORD_records_get_size(unsigned int rd_count,
88                                   const struct GNUNET_GNSRECORD_Data *rd)
89 {
90   size_t ret;
91
92   if (0 == rd_count)
93     return 0;
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   //Do not pad PKEY
126   if (GNUNET_GNSRECORD_TYPE_PKEY == rd->record_type)
127     return ret;
128   /**
129    * Efficiently round up to the next
130    * power of 2 for padding
131    * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
132    */
133   ret--;
134   ret |= ret >> 1;
135   ret |= ret >> 2;
136   ret |= ret >> 4;
137   ret |= ret >> 8;
138   ret |= ret >> 16;
139   ret++;
140   return (ssize_t)ret;
141 }
142
143
144 /**
145  * Serialize the given records to the given destination buffer.
146  *
147  * @param rd_count number of records in the rd array
148  * @param rd array of #GNUNET_GNSRECORD_Data with @a rd_count elements
149  * @param dest_size size of the destination array
150  * @param dest where to write the result
151  * @return the size of serialized records, -1 if records do not fit
152  */
153 ssize_t
154 GNUNET_GNSRECORD_records_serialize(unsigned int rd_count,
155                                    const struct GNUNET_GNSRECORD_Data *rd,
156                                    size_t dest_size,
157                                    char *dest)
158 {
159   struct NetworkRecord rec;
160   size_t off;
161
162   off = 0;
163   for (unsigned int i = 0; i < rd_count; i++)
164     {
165       LOG(GNUNET_ERROR_TYPE_DEBUG,
166           "Serializing record %u with flags %d and expiration time %llu\n",
167           i,
168           rd[i].flags,
169           (unsigned long long)rd[i].expiration_time);
170       rec.expiration_time = GNUNET_htonll(rd[i].expiration_time);
171       rec.data_size = htonl((uint32_t)rd[i].data_size);
172       rec.record_type = htonl(rd[i].record_type);
173       rec.flags = htonl(rd[i].flags);
174       if ((off + sizeof(rec) > dest_size) ||
175           (off + sizeof(rec) < off))
176         {
177           GNUNET_break(0);
178           return -1;
179         }
180       GNUNET_memcpy(&dest[off],
181                     &rec,
182                     sizeof(rec));
183       off += sizeof(rec);
184       if ((off + rd[i].data_size > dest_size) ||
185           (off + rd[i].data_size < off))
186         {
187           GNUNET_break(0);
188           return -1;
189         }
190       GNUNET_memcpy(&dest[off],
191                     rd[i].data,
192                     rd[i].data_size);
193       off += rd[i].data_size;
194 #if DEBUG_GNSRECORDS
195       {
196         char *str;
197
198         str = GNUNET_GNSRECORD_value_to_string(rd[i].record_type,
199                                                rd[i].data,
200                                                rd[i].data_size);
201         if (NULL == str)
202           {
203             GNUNET_break_op(0);
204             return -1;
205           }
206         GNUNET_free(str);
207       }
208 #endif
209     }
210   memset(&dest[off],
211          0,
212          dest_size - off);
213   return dest_size;
214 }
215
216
217 /**
218  * Deserialize the given records to the given destination.
219  *
220  * @param len size of the serialized record data
221  * @param src the serialized record data
222  * @param rd_count number of records in the rd array
223  * @param dest where to put the data
224  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
225  */
226 int
227 GNUNET_GNSRECORD_records_deserialize(size_t len,
228                                      const char *src,
229                                      unsigned int rd_count,
230                                      struct GNUNET_GNSRECORD_Data *dest)
231 {
232   struct NetworkRecord rec;
233   size_t off;
234
235   off = 0;
236   for (unsigned int i = 0; i < rd_count; i++)
237     {
238       if ((off + sizeof(rec) > len) ||
239           (off + sizeof(rec) < off))
240         {
241           GNUNET_break_op(0);
242           return GNUNET_SYSERR;
243         }
244       GNUNET_memcpy(&rec,
245                     &src[off],
246                     sizeof(rec));
247       dest[i].expiration_time = GNUNET_ntohll(rec.expiration_time);
248       dest[i].data_size = ntohl((uint32_t)rec.data_size);
249       dest[i].record_type = ntohl(rec.record_type);
250       dest[i].flags = ntohl(rec.flags);
251       off += sizeof(rec);
252       if ((off + dest[i].data_size > len) ||
253           (off + dest[i].data_size < off))
254         {
255           GNUNET_break_op(0);
256           return GNUNET_SYSERR;
257         }
258       dest[i].data = &src[off];
259       off += dest[i].data_size;
260 #if GNUNET_EXTRA_LOGGING
261       {
262         char *str;
263
264         str = GNUNET_GNSRECORD_value_to_string(dest[i].record_type,
265                                                dest[i].data,
266                                                dest[i].data_size);
267         if (NULL == str)
268           {
269             GNUNET_break_op(0);
270             return GNUNET_SYSERR;
271           }
272         GNUNET_free(str);
273       }
274 #endif
275       LOG(GNUNET_ERROR_TYPE_DEBUG,
276           "Deserialized record %u with flags %d and expiration time %llu\n",
277           i,
278           dest[i].flags,
279           (unsigned long long)dest[i].expiration_time);
280     }
281   return GNUNET_OK;
282 }
283
284
285 /* end of gnsrecord_serialization.c */