uncrustify as demanded.
[oweals/gnunet.git] / src / util / peer.c
1 /*
2       This file is part of GNUnet
3      Copyright (C) 2006, 2008, 2009 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 util/peer.c
23  * @brief peer-ID table that assigns integer IDs to peer-IDs to save memory
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_peer_lib.h"
28
29 #define LOG(kind, ...) GNUNET_log_from(kind, "util-peer", __VA_ARGS__)
30
31
32 struct PeerEntry {
33   /**
34    * The identifier itself
35    */
36   struct GNUNET_PeerIdentity id;
37
38   /**
39    * Short version of the identifier; if the RC==0, then index of next
40    * free slot in table, otherwise equal to this slot in the table.
41    */
42   GNUNET_PEER_Id pid;
43
44   /**
45    * Reference counter, 0 if this slot is not used.
46    */
47   unsigned int rc;
48 };
49
50
51 /**
52  * Table with our interned peer IDs.
53  */
54 static struct PeerEntry **table;
55
56 /**
57  * Peermap of PeerIdentities to "struct PeerEntry"
58  * (for fast lookup).  NULL until the library
59  * is actually being used.
60  */
61 static struct GNUNET_CONTAINER_MultiPeerMap *map;
62
63 /**
64  * Size of the "table".
65  */
66 static unsigned int size;
67
68 /**
69  * Index of the beginning of the free list in the table; set to "size"
70  * if no slots are free in the table.
71  */
72 static unsigned int free_list_start;
73
74
75 /**
76  * Search for a peer identity. The reference counter is not changed.
77  *
78  * @param pid identity to find
79  * @return the interned identity or 0.
80  */
81 GNUNET_PEER_Id
82 GNUNET_PEER_search(const struct GNUNET_PeerIdentity *pid)
83 {
84   struct PeerEntry *e;
85
86   if (NULL == pid)
87     return 0;
88   if (NULL == map)
89     return 0;
90   e = GNUNET_CONTAINER_multipeermap_get(map, pid);
91   if (NULL == e)
92     return 0;
93   GNUNET_assert(e->rc > 0);
94   return e->pid;
95 }
96
97
98 /**
99  * Intern an peer identity.  If the identity is already known, its
100  * reference counter will be increased by one.
101  *
102  * @param pid identity to intern
103  * @return the interned identity.
104  */
105 GNUNET_PEER_Id
106 GNUNET_PEER_intern(const struct GNUNET_PeerIdentity *pid)
107 {
108   GNUNET_PEER_Id ret;
109   struct PeerEntry *e;
110   unsigned int i;
111
112   if (NULL == pid)
113     return 0;
114   if (NULL == map)
115     map = GNUNET_CONTAINER_multipeermap_create(32, GNUNET_YES);
116   e = GNUNET_CONTAINER_multipeermap_get(map, pid);
117   if (NULL != e)
118     {
119       GNUNET_assert(e->rc > 0);
120       e->rc++;
121       return e->pid;
122     }
123   ret = free_list_start;
124   if (ret == size)
125     {
126       GNUNET_array_grow(table, size, size + 16);
127       for (i = ret; i < size; i++)
128         {
129           table[i] = GNUNET_new(struct PeerEntry);
130           table[i]->pid = i + 1;
131         }
132     }
133   if (0 == ret)
134     {
135       memset(&table[0]->id, 0, sizeof(struct GNUNET_PeerIdentity));
136       table[0]->pid = 0;
137       table[0]->rc = 1;
138       ret = 1;
139     }
140   GNUNET_assert(ret < size);
141   GNUNET_assert(0 == table[ret]->rc);
142   free_list_start = table[ret]->pid;
143   table[ret]->id = *pid;
144   table[ret]->rc = 1;
145   table[ret]->pid = ret;
146   GNUNET_break(GNUNET_OK ==
147                GNUNET_CONTAINER_multipeermap_put(map,
148                                                  &table[ret]->id,
149                                                  table[ret],
150                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
151   return ret;
152 }
153
154
155 /**
156  * Decrement multiple RCs of peer identities by one.
157  *
158  * @param ids array of PIDs to decrement the RCs of
159  * @param count size of the ids array
160  */
161 void
162 GNUNET_PEER_decrement_rcs(const GNUNET_PEER_Id *ids, unsigned int count)
163 {
164   int i;
165   GNUNET_PEER_Id id;
166
167   if (0 == count)
168     return;
169   for (i = count - 1; i >= 0; i--)
170     {
171       id = ids[i];
172       if (0 == id)
173         continue;
174       GNUNET_assert(id < size);
175       GNUNET_assert(table[id]->rc > 0);
176       table[id]->rc--;
177       if (0 == table[id]->rc)
178         {
179           GNUNET_break(GNUNET_OK ==
180                        GNUNET_CONTAINER_multipeermap_remove(map,
181                                                             &table[id]->id,
182                                                             table[id]));
183           table[id]->pid = free_list_start;
184           free_list_start = id;
185         }
186     }
187 }
188
189
190 /**
191  * Change the reference counter of an interned PID.
192  *
193  * @param id identity to change the RC of
194  * @param delta how much to change the RC
195  */
196 void
197 GNUNET_PEER_change_rc(GNUNET_PEER_Id id, int delta)
198 {
199   if (0 == id)
200     return;
201   GNUNET_assert(id < size);
202   GNUNET_assert(table[id]->rc > 0);
203   GNUNET_assert((delta >= 0) ||
204                 (table[id]->rc >= (unsigned int)(-delta)));
205   table[id]->rc += delta;
206   if (0 == table[id]->rc)
207     {
208       GNUNET_break(GNUNET_OK ==
209                    GNUNET_CONTAINER_multipeermap_remove(map,
210                                                         &table[id]->id,
211                                                         table[id]));
212       table[id]->pid = free_list_start;
213       free_list_start = id;
214     }
215 }
216
217
218 /**
219  * Convert an interned PID to a normal peer identity.
220  *
221  * @param id interned PID to convert
222  * @param pid where to write the normal peer identity
223  */
224 void
225 GNUNET_PEER_resolve(GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid)
226 {
227   if (0 == id)
228     {
229       memset(pid, 0, sizeof(struct GNUNET_PeerIdentity));
230       return;
231     }
232   GNUNET_assert(id < size);
233   GNUNET_assert(table[id]->rc > 0);
234   *pid = table[id]->id;
235 }
236
237
238 /**
239  * Convert an interned PID to a normal peer identity.
240  *
241  * @param id interned PID to convert
242  * @return pointer to peer identity, valid as long 'id' is valid
243  */
244 const struct GNUNET_PeerIdentity *
245 GNUNET_PEER_resolve2(GNUNET_PEER_Id id)
246 {
247   GNUNET_assert(id < size);
248   GNUNET_assert(table[id]->rc > 0);
249   return &table[id]->id;
250 }
251
252
253
254 /* end of peer.c */