Remove superflous heap allocation
[oweals/gnunet.git] / src / peerstore / peerstore_common.c
1 /*
2       This file is part of GNUnet
3       (C) 2012-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  * @file peerstore/peerstore_common.c
22  * @brief Helper peerstore functions
23  * @author Omar Tarabai
24  */
25
26 #include "peerstore_common.h"
27
28 /**
29  * Creates a hash of the given key combination
30  *
31  */
32 void
33 PEERSTORE_hash_key (const char *sub_system,
34                     const struct GNUNET_PeerIdentity *peer, const char *key,
35                     struct GNUNET_HashCode *ret)
36 {
37   size_t sssize;
38   size_t psize;
39   size_t ksize;
40   size_t totalsize;
41   void *block;
42   void *blockptr;
43
44   sssize = strlen (sub_system) + 1;
45   psize = sizeof (struct GNUNET_PeerIdentity);
46   ksize = strlen (key) + 1;
47   totalsize = sssize + psize + ksize;
48   block = GNUNET_malloc (totalsize);
49   blockptr = block;
50   memcpy (blockptr, sub_system, sssize);
51   blockptr += sssize;
52   memcpy (blockptr, peer, psize);
53   blockptr += psize;
54   memcpy (blockptr, key, ksize);
55   GNUNET_CRYPTO_hash (block, totalsize, ret);
56   GNUNET_free (block);
57 }
58
59
60 /**
61  * Creates a record message ready to be sent
62  *
63  * @param sub_system sub system string
64  * @param peer Peer identity (can be NULL)
65  * @param key record key string (can be NULL)
66  * @param value record value BLOB (can be NULL)
67  * @param value_size record value size in bytes (set to 0 if value is NULL)
68  * @param expiry absolute time after which the record expires
69  * @param msg_type message type to be set in header
70  * @return pointer to record message struct
71  */
72 struct StoreRecordMessage *
73 PEERSTORE_create_record_message (const char *sub_system,
74                                  const struct GNUNET_PeerIdentity *peer,
75                                  const char *key, const void *value,
76                                  size_t value_size,
77                                  struct GNUNET_TIME_Absolute *expiry,
78                                  uint16_t msg_type)
79 {
80   struct StoreRecordMessage *srm;
81   size_t ss_size;
82   size_t key_size;
83   size_t request_size;
84   void *dummy;
85
86   ss_size = strlen (sub_system) + 1;
87   if (NULL == key)
88     key_size = 0;
89   else
90     key_size = strlen (key) + 1;
91   request_size =
92       sizeof (struct StoreRecordMessage) + ss_size + key_size + value_size;
93   srm = GNUNET_malloc (request_size);
94   srm->header.size = htons (request_size);
95   srm->header.type = htons (msg_type);
96   srm->key_size = htons (key_size);
97   if (NULL != expiry)
98     srm->expiry = *expiry;
99   if (NULL == peer)
100     srm->peer_set = htons (GNUNET_NO);
101   else
102   {
103     srm->peer_set = htons (GNUNET_YES);
104     srm->peer = *peer;
105   }
106   srm->sub_system_size = htons (ss_size);
107   srm->value_size = htons (value_size);
108   dummy = &srm[1];
109   memcpy (dummy, sub_system, ss_size);
110   dummy += ss_size;
111   memcpy (dummy, key, key_size);
112   dummy += key_size;
113   memcpy (dummy, value, value_size);
114   return srm;
115 }
116
117
118 /**
119  * Creates a MQ envelope for a single record
120  *
121  * @param sub_system sub system string
122  * @param peer Peer identity (can be NULL)
123  * @param key record key string (can be NULL)
124  * @param value record value BLOB (can be NULL)
125  * @param value_size record value size in bytes (set to 0 if value is NULL)
126  * @param expiry time after which the record expires
127  * @param options options specific to the storage operation
128  * @param msg_type message type to be set in header
129  * @return pointer to record message struct
130  */
131 struct GNUNET_MQ_Envelope *
132 PEERSTORE_create_record_mq_envelope (const char *sub_system,
133                                      const struct GNUNET_PeerIdentity *peer,
134                                      const char *key, const void *value,
135                                      size_t value_size,
136                                      struct GNUNET_TIME_Absolute *expiry,
137                                      enum GNUNET_PEERSTORE_StoreOption options,
138                                      uint16_t msg_type)
139 {
140   struct StoreRecordMessage *srm;
141   struct GNUNET_MQ_Envelope *ev;
142   size_t ss_size;
143   size_t key_size;
144   size_t msg_size;
145   void *dummy;
146
147   GNUNET_assert (NULL != sub_system);
148   ss_size = strlen (sub_system) + 1;
149   if (NULL == key)
150     key_size = 0;
151   else
152     key_size = strlen (key) + 1;
153   msg_size = ss_size + key_size + value_size;
154   ev = GNUNET_MQ_msg_extra (srm, msg_size, msg_type);
155   srm->key_size = htons (key_size);
156   if (NULL != expiry)
157     srm->expiry = *expiry;
158   if (NULL == peer)
159     srm->peer_set = htons (GNUNET_NO);
160   else
161   {
162     srm->peer_set = htons (GNUNET_YES);
163     srm->peer = *peer;
164   }
165   srm->sub_system_size = htons (ss_size);
166   srm->value_size = htons (value_size);
167   srm->options = htonl (options);
168   dummy = &srm[1];
169   memcpy (dummy, sub_system, ss_size);
170   dummy += ss_size;
171   memcpy (dummy, key, key_size);
172   dummy += key_size;
173   memcpy (dummy, value, value_size);
174   return ev;
175 }
176
177
178 /**
179  * Parses a message carrying a record
180  *
181  * @param message the actual message
182  * @return Pointer to record or NULL if error
183  */
184 struct GNUNET_PEERSTORE_Record *
185 PEERSTORE_parse_record_message (const struct GNUNET_MessageHeader *message)
186 {
187   struct StoreRecordMessage *srm;
188   struct GNUNET_PEERSTORE_Record *record;
189   uint16_t req_size;
190   uint16_t ss_size;
191   uint16_t key_size;
192   uint16_t value_size;
193   char *dummy;
194
195   req_size = ntohs (message->size);
196   if (req_size < sizeof (struct StoreRecordMessage))
197   {
198     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
199                 "Received message with invalid size: (%d < %d).\n", req_size,
200                 sizeof (struct StoreRecordMessage));
201     return NULL;
202   }
203   srm = (struct StoreRecordMessage *) message;
204   ss_size = ntohs (srm->sub_system_size);
205   key_size = ntohs (srm->key_size);
206   value_size = ntohs (srm->value_size);
207   if (ss_size + key_size + value_size + sizeof (struct StoreRecordMessage) !=
208       req_size)
209   {
210     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
211                 "Received message with invalid sizes: (%d + %d + %d + %d != %d).\n",
212                 ss_size, key_size, value_size,
213                 sizeof (struct StoreRecordMessage), req_size);
214     return NULL;
215   }
216   record = GNUNET_new (struct GNUNET_PEERSTORE_Record);
217   if (GNUNET_YES == ntohs (srm->peer_set))
218   {
219     record->peer = GNUNET_new (struct GNUNET_PeerIdentity);
220
221     memcpy (record->peer, &srm->peer, sizeof (struct GNUNET_PeerIdentity));
222   }
223   record->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
224
225   *(record->expiry) = srm->expiry;
226   dummy = (char *) &srm[1];
227   if (ss_size > 0)
228   {
229     record->sub_system = GNUNET_strdup (dummy);
230     dummy += ss_size;
231   }
232   if (key_size > 0)
233   {
234     record->key = GNUNET_strdup (dummy);
235     dummy += key_size;
236   }
237   if (value_size > 0)
238   {
239     record->value = GNUNET_malloc (value_size);
240     memcpy (record->value, dummy, value_size);
241   }
242   record->value_size = value_size;
243   return record;
244 }
245
246
247 /**
248  * Free any memory allocated for this record
249  *
250  * @param record
251  */
252 void
253 PEERSTORE_destroy_record (struct GNUNET_PEERSTORE_Record *record)
254 {
255   if (NULL != record->sub_system)
256     GNUNET_free (record->sub_system);
257   if (NULL != record->peer)
258     GNUNET_free (record->peer);
259   if (NULL != record->key)
260     GNUNET_free (record->key);
261   if (NULL != record->value)
262   {
263     GNUNET_free (record->value);
264     record->value = 0;
265   }
266   if (NULL != record->expiry)
267     GNUNET_free (record->expiry);
268   GNUNET_free (record);
269 }