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