1 /*
2 * Copyright (C) 2013-2014 Philipp Marek <philipp.marek@linbit.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifndef _INLINE_FN_H
20 #define _INLINE_FN_H
21
22 #include <time.h>
23 #include <sys/time.h>
24 #include <assert.h>
25 #include <string.h>
26 #include "timer.h"
27 #include "config.h"
28 #include "transport.h"
29
30
31
32 inline static int get_local_id(void)
33 {
34 return local ? local->site_id : -1;
35 }
36
37
38 inline static uint32_t get_node_id(struct booth_site *node)
39 {
40 return node ? node->site_id : 0;
41 }
42
43
44 /** Returns number of seconds left, if any. */
45 inline static int term_time_left(struct ticket_config *tk)
46 {
47 int left = 0;
48
49 if (is_time_set(&tk->term_expires)) {
50 left = time_left(&tk->term_expires);
51 }
52 return (left < 0) ? 0 : left;
53 }
54
55
56 inline static int leader_and_valid(struct ticket_config *tk)
57 {
58 if (tk->leader != local)
59 return 0;
60
61 return term_time_left(tk);
62 }
63
64
65 /** Is this some leader? */
66 inline static int is_owned(const struct ticket_config *tk)
67 {
68 return (tk->leader && tk->leader != no_leader);
69 }
70
71 inline static int is_resend(struct ticket_config *tk)
72 {
73 timetype now;
74
75 get_time(&now);
76 return time_sub_int(&now, &tk->req_sent_at) >= tk->timeout;
77 }
78
79
80 static inline void init_header_bare(struct boothc_header *h) {
81 timetype now;
82
83 assert(local && local->site_id);
84 h->magic = htonl(BOOTHC_MAGIC);
85 h->version = htonl(BOOTHC_VERSION);
86 h->from = htonl(local->site_id);
87 if (is_auth_req()) {
88 get_time(&now);
89 h->opts = htonl(BOOTH_OPT_AUTH);
|
(1) Event store_truncates_time_t: |
A "time_t" value is stored in an integer with too few bits to accommodate it. The expression "secs_since_epoch(&now)" is cast to "__uint32_t". |
90 h->secs = htonl(secs_since_epoch(&now));
91 h->usecs = htonl(get_usecs(&now));
92 } else {
93 h->opts = htonl(0);
94 h->secs = htonl(0);
95 h->usecs = htonl(0);
96 }
97 }
98
99 /* get the _real_ message length out of the header
100 */
101 #define sendmsglen(msg) ntohl((msg)->header.length)
102
103 static inline void init_header(struct boothc_header *h,
104 int cmd, int request, int options,
105 int result, int reason, int data_len)
106 {
107 init_header_bare(h);
108 h->length = htonl(data_len -
109 (is_auth_req() ? 0 : sizeof(struct hmac)));
110 h->cmd = htonl(cmd);
111 h->request = htonl(request);
112 h->options = htonl(options);
113 h->result = htonl(result);
114 h->reason = htonl(reason);
115 }
116
117 #define my_last_term(tk) \
118 (((tk)->state == ST_CANDIDATE && (tk)->last_valid_tk) ? \
119 (tk)->last_valid_tk->current_term : (tk)->current_term)
120
121 extern int TIME_RES, TIME_MULT;
122
123 #define msg_term_time(msg) \
124 ntohl((msg)->ticket.term_valid_for)*TIME_RES/TIME_MULT
125 #define set_msg_term_time(msg, tk) \
126 (msg)->ticket.term_valid_for = htonl(term_time_left(tk)*TIME_MULT/TIME_RES)
127
128 static inline void init_ticket_msg(struct boothc_ticket_msg *msg,
129 int cmd, int request, int rv, int reason,
130 struct ticket_config *tk)
131 {
132 assert(sizeof(msg->ticket.id) == sizeof(tk->name));
133
134 init_header(&msg->header, cmd, request, 0, rv, reason, sizeof(*msg));
135
136 if (!tk) {
137 memset(&msg->ticket, 0, sizeof(msg->ticket));
138 } else {
139 memcpy(msg->ticket.id, tk->name, sizeof(msg->ticket.id));
140
141 msg->ticket.leader = htonl(get_node_id(
142 (tk->leader && tk->leader != no_leader) ? tk->leader :
143 (tk->voted_for ? tk->voted_for : no_leader)));
144 msg->ticket.term = htonl(tk->current_term);
145 set_msg_term_time(msg, tk);
146 }
147 }
148
149
150 static inline struct booth_transport const *transport(void)
151 {
152 return booth_transport + booth_conf->proto;
153 }
154
155
156 static inline const char *site_string(const struct booth_site *site)
157 {
158 return site ? site->addr_string : "NONE";
159 }
160
161
162 static inline uint16_t site_port(const struct booth_site *site)
163 {
164 assert(site != NULL);
165
166 if (site->family == AF_INET) {
167 return ntohs(site->sa4.sin_port);
168 } else if (site->family == AF_INET6) {
169 return ntohs(site->sa6.sin6_port);
170 } else {
171 return 0;
172 }
173 }
174
175
176 static inline const char *ticket_leader_string(struct ticket_config *tk)
177 {
178 return site_string(tk->leader);
179 }
180
181
182 /* We allow half of the uint32_t to be used;
183 * half of that below, half of that above the current known "good" value.
184 * 0 UINT32_MAX
185 * |--------------------------+----------------+------------|
186 * | | |
187 * |--------+-------| allowed range
188 * |
189 * current commit index
190 *
191 * So, on overflow it looks like that:
192 * UINT32_MAX 0
193 * |--------------------------+-----------||---+------------|
194 * | | |
195 * |--------+-------| allowed range
196 * |
197 * current commit index
198 *
199 * This should be possible by using the same datatype and relying
200 * on the under/overflow semantics.
201 *
202 *
203 * Having 30 bits available, and assuming an expire time of
204 * one minute and a (high) commit index step of 64 == 2^6 (because
205 * of weights), we get 2^24 minutes of range - which is ~750
206 * years. "Should be enough for everybody."
207 */
208 static inline int index_is_higher_than(uint32_t c_high, uint32_t c_low)
209 {
210 uint32_t diff;
211
212 if (c_high == c_low)
213 return 0;
214
215 diff = c_high - c_low;
216 if (diff < UINT32_MAX/4)
217 return 1;
218
219 diff = c_low - c_high;
220 if (diff < UINT32_MAX/4)
221 return 0;
222
223 assert(!"commit index out of range - invalid");
224 }
225
226
227 static inline uint32_t index_max2(uint32_t a, uint32_t b)
228 {
229 return index_is_higher_than(a, b) ? a : b;
230 }
231
232 static inline uint32_t index_max3(uint32_t a, uint32_t b, uint32_t c)
233 {
234 return index_max2( index_max2(a, b), c);
235 }
236
237
238 /* only invoked when ticket leader */
239 static inline void get_next_election_time(struct ticket_config *tk, timetype *next)
240 {
241 assert(tk->leader == local);
242
243 /* if last_renewal is not set, which is unusual, it may mean
244 * that the ticket never got updated, i.e. nobody acked
245 * ticket updates (say, due to a temporary connection
246 * problem)
247 * we may try a bit later again */
248 if (!is_time_set(&tk->last_renewal)) {
249 time_reset(next);
250 } else {
251 interval_add(&tk->last_renewal, tk->renewal_freq, next);
252 }
253
254 /* if delay_commit is earlier than next, then set next to
255 * delay_commit */
256 if (is_time_set(&tk->delay_commit) &&
257 time_cmp(next, &tk->delay_commit, >)) {
258 copy_time(&tk->delay_commit, next);
259 }
260 }
261
262
263 static inline void expect_replies(struct ticket_config *tk,
264 int reply_type)
265 {
266 tk->retry_number = 0;
267 tk->acks_expected = reply_type;
268 tk->acks_received = local->bitmask;
269 get_time(&tk->req_sent_at);
270 }
271
272 static inline void no_resends(struct ticket_config *tk)
273 {
274 tk->retry_number = 0;
275 tk->acks_expected = 0;
276 }
277
278 static inline struct booth_site *my_vote(struct ticket_config *tk)
279 {
280 return tk->votes_for[ local->index ];
281 }
282
283
284 static inline int count_bits(uint64_t val) {
285 return __builtin_popcount(val);
286 }
287
288 static inline int majority_of_bits(struct ticket_config *tk, uint64_t val)
289 {
290 /* Use ">" to get majority decision, even for an even number
291 * of participants. */
292 return count_bits(val) * 2 >
293 booth_conf->site_count;
294 }
295
296
297 static inline int all_replied(struct ticket_config *tk)
298 {
299 return !(tk->acks_received ^ booth_conf->all_bits);
300 }
301
302 static inline int all_sites_replied(struct ticket_config *tk)
303 {
304 return !((tk->acks_received & booth_conf->sites_bits) ^ booth_conf->sites_bits);
305 }
306
307
308 #endif
309