sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

sync_object.c (6479B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file util/sync_object.c
     18  * @brief shared logic for object JSON parsing and serialization
     19  * @author Iván Ávalos
     20  */
     21 #include "platform.h"
     22 #include <gnunet/gnunet_common.h>
     23 #include <gnunet/gnunet_json_lib.h>
     24 #include <jansson.h>
     25 #include <taler/taler_json_lib.h>
     26 #include <sync/sync_util.h>
     27 
     28 
     29 enum GNUNET_GenericReturnValue
     30 SYNC_object_entry_parse (
     31   json_t *input,
     32   struct SYNC_ObjectEntry *entry)
     33 {
     34   struct GNUNET_JSON_Specification espec[] = {
     35     GNUNET_JSON_spec_fixed_auto ("uid",
     36                                  &entry->uid),
     37     GNUNET_JSON_spec_varsize ("data",
     38                               &entry->data,
     39                               &entry->data_size),
     40     GNUNET_JSON_spec_end ()
     41   };
     42   enum GNUNET_GenericReturnValue res;
     43   const char *ename;
     44   unsigned int eline;
     45 
     46   res = GNUNET_JSON_parse (input,
     47                            espec,
     48                            &ename,
     49                            &eline);
     50   if (GNUNET_OK != res)
     51   {
     52     GNUNET_break_op (0);
     53     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     54                 "Failed to parse object entry at field %s\n",
     55                 ename);
     56     return GNUNET_SYSERR;
     57   }
     58   return GNUNET_OK;
     59 }
     60 
     61 
     62 void
     63 SYNC_object_entry_clear (
     64   struct SYNC_ObjectEntry *entry)
     65 {
     66   GNUNET_free (entry->data);
     67   entry->data = NULL;
     68   entry->data_size = 0;
     69 }
     70 
     71 
     72 json_t *
     73 SYNC_object_entry_serialize (
     74   const struct SYNC_ObjectUID *uid,
     75   size_t data_size,
     76   const void *data)
     77 {
     78   return GNUNET_JSON_PACK (
     79     GNUNET_JSON_pack_data_auto ("uid",
     80                                 uid),
     81     GNUNET_JSON_pack_data_varsize ("data",
     82                                    data,
     83                                    data_size));
     84 }
     85 
     86 
     87 json_t *
     88 SYNC_object_refs_serialize (
     89   size_t refs_len,
     90   const struct SYNC_ObjectUID *object_uids,
     91   const int16_t *object_incs)
     92 {
     93   json_t *refs;
     94 
     95   if (0 == refs_len)
     96     return NULL;
     97   refs = json_object ();
     98   GNUNET_assert (NULL != refs);
     99   for (size_t i = 0; i < refs_len; i++)
    100   {
    101     char *key;
    102 
    103     key = GNUNET_STRINGS_data_to_string_alloc (&object_uids[i],
    104                                                sizeof (object_uids[i]));
    105     GNUNET_assert (0 ==
    106                    json_object_set_new (refs,
    107                                         key,
    108                                         json_integer (object_incs[i])));
    109     GNUNET_free (key);
    110   }
    111   return refs;
    112 }
    113 
    114 
    115 GNUNET_NETWORK_STRUCT_BEGIN
    116 
    117 /**
    118  * One object reference, as hashed for the signatures.
    119  */
    120 struct SYNC_ObjectRefP
    121 {
    122   /**
    123    * UID of the referenced object.
    124    */
    125   struct SYNC_ObjectUID uid;
    126 
    127   /**
    128    * Reference count adjustment, in network byte order.
    129    */
    130   int16_t inc GNUNET_PACKED;
    131 };
    132 
    133 GNUNET_NETWORK_STRUCT_END
    134 
    135 
    136 /**
    137  * Compare two object references by UID, for #qsort().
    138  *
    139  * @param a first `struct SYNC_ObjectRefP`
    140  * @param b second `struct SYNC_ObjectRefP`
    141  * @return negative/zero/positive as @a a sorts before/equal/after @a b
    142  */
    143 static int
    144 ref_cmp (const void *a,
    145          const void *b)
    146 {
    147   const struct SYNC_ObjectRefP *ra = a;
    148   const struct SYNC_ObjectRefP *rb = b;
    149 
    150   return memcmp (&ra->uid,
    151                  &rb->uid,
    152                  sizeof (ra->uid));
    153 }
    154 
    155 
    156 enum GNUNET_GenericReturnValue
    157 SYNC_object_refs_hash (
    158   size_t refs_len,
    159   const struct SYNC_ObjectUID *object_uids,
    160   const int16_t *object_incs,
    161   struct GNUNET_HashCode *refs_hash)
    162 {
    163   struct SYNC_ObjectRefP *refs;
    164 
    165   if (0 == refs_len)
    166   {
    167     GNUNET_CRYPTO_hash ("",
    168                         0,
    169                         refs_hash);
    170     return GNUNET_OK;
    171   }
    172   refs = GNUNET_new_array (refs_len,
    173                            struct SYNC_ObjectRefP);
    174   for (size_t i = 0; i < refs_len; i++)
    175   {
    176     refs[i].uid = object_uids[i];
    177     refs[i].inc = htons ((uint16_t) object_incs[i]);
    178   }
    179   qsort (refs,
    180          refs_len,
    181          sizeof (struct SYNC_ObjectRefP),
    182          &ref_cmp);
    183   for (size_t i = 1; i < refs_len; i++)
    184   {
    185     if (0 == ref_cmp (&refs[i - 1],
    186                       &refs[i]))
    187     {
    188       GNUNET_break (0);
    189       GNUNET_free (refs);
    190       return GNUNET_SYSERR;
    191     }
    192   }
    193   GNUNET_CRYPTO_hash (refs,
    194                       refs_len * sizeof (struct SYNC_ObjectRefP),
    195                       refs_hash);
    196   GNUNET_free (refs);
    197   return GNUNET_OK;
    198 }
    199 
    200 
    201 enum GNUNET_GenericReturnValue
    202 SYNC_object_refs_parse (
    203   const json_t *refs,
    204   size_t *refs_len,
    205   struct SYNC_ObjectUID **object_uids,
    206   int16_t **object_incs)
    207 {
    208   struct SYNC_ObjectUID *uids;
    209   int16_t *incs;
    210   size_t len;
    211   size_t i;
    212   const char *key;
    213   json_t *value;
    214 
    215   if (NULL == refs)
    216   {
    217     *refs_len = 0;
    218     *object_uids = NULL;
    219     *object_incs = NULL;
    220     return GNUNET_OK;
    221   }
    222   if (! json_is_object (refs))
    223   {
    224     GNUNET_break_op (0);
    225     return GNUNET_SYSERR;
    226   }
    227   len = json_object_size (refs);
    228   if (0 == len)
    229   {
    230     *refs_len = 0;
    231     *object_uids = NULL;
    232     *object_incs = NULL;
    233     return GNUNET_OK;
    234   }
    235   uids = GNUNET_new_array (len,
    236                            struct SYNC_ObjectUID);
    237   incs = GNUNET_new_array (len,
    238                            int16_t);
    239   i = 0;
    240   json_object_foreach ((json_t *) refs, key, value)
    241   {
    242     json_int_t inc;
    243 
    244     if (GNUNET_OK !=
    245         GNUNET_STRINGS_string_to_data (key,
    246                                        strlen (key),
    247                                        &uids[i],
    248                                        sizeof (uids[i])))
    249     {
    250       GNUNET_break_op (0);
    251       goto fail;
    252     }
    253     if (! json_is_integer (value))
    254     {
    255       GNUNET_break_op (0);
    256       goto fail;
    257     }
    258     inc = json_integer_value (value);
    259     if ( (inc < INT16_MIN) ||
    260          (inc > INT16_MAX) )
    261     {
    262       GNUNET_break_op (0);
    263       goto fail;
    264     }
    265     incs[i] = (int16_t) inc;
    266     i++;
    267   }
    268   *refs_len = len;
    269   *object_uids = uids;
    270   *object_incs = incs;
    271   return GNUNET_OK;
    272 fail:
    273   GNUNET_free (uids);
    274   GNUNET_free (incs);
    275   return GNUNET_SYSERR;
    276 }