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