1    	/*
2    	 * Copyright (C) 2011 Red Hat, Inc.
3    	 *
4    	 * Author: Angus Salkeld <asalkeld@redhat.com>
5    	 *
6    	 * This file is part of libqb.
7    	 *
8    	 * libqb is free software: you can redistribute it and/or modify
9    	 * it under the terms of the GNU Lesser General Public License as published by
10   	 * the Free Software Foundation, either version 2.1 of the License, or
11   	 * (at your option) any later version.
12   	 *
13   	 * libqb is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	 * GNU Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public License
19   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20   	 */
21   	#include <os_base.h>
22   	#include <assert.h>
23   	
24   	#include <qb/qbdefs.h>
25   	#include <qb/qbmap.h>
26   	#include "map_int.h"
27   	
28   	#define SKIPLIST_LEVEL_MAX 8
29   	#define SKIPLIST_LEVEL_MIN 0
30   	/* The amount of possible levels */
31   	#define SKIPLIST_LEVEL_COUNT (SKIPLIST_LEVEL_MAX - SKIPLIST_LEVEL_MIN + 1)
32   	
33   	struct skiplist_iter {
34   		struct qb_map_iter i;
35   		struct skiplist_node *n;
36   	};
37   	
38   	struct skiplist_node {
39   		const char *key;
40   		void *value;
41   		/* special meaning when lower than SKIPLIST_LEVEL_MIN:
42   		   indication that @skiplist_node_destroy() needs to skip
43   		   disposing node->forward (unless it is the termination
44   		   of the whole list) */
45   		int8_t level;
46   		uint32_t refcount;
47   		struct qb_list_head notifier_head;
48   	
49   		/* An array of @level + 1 node pointers */
50   		struct skiplist_node **forward;
51   	};
52   	
53   	struct skiplist {
54   		struct qb_map map;
55   	
56   		size_t length;
57   		/* special meaning when lower than SKIPLIST_LEVEL_MIN:
58   		   indication that @skiplist_node_destroy() is the terminating
59   		   one (triggered with @skiplist_destroy()), therefore node->forward
60   		   needs to be free'd unconditionally */
61   		int8_t level;
62   		struct skiplist_node *header;
63   	};
64   	
65   	/* An array of nodes that need to be updated after an insert or delete operation
66   	 */
67   	typedef struct skiplist_node *skiplist_update_t[SKIPLIST_LEVEL_COUNT];
68   	
69   	static int8_t
70   	skiplist_level_generate(void)
71   	{
72   		/* This constant is found by 1 / P, where P = 0.25. */
73   		enum { P_INVERSE = 4 };
74   	
75   		/* The original algorithm's random number is in the range [0, 1), so
76   		 * max M = 1. Its ceiling C = M * P = 1 * P = P.
77   		 *
78   		 * Our random number is in the range [0, UINT16_MAX], so M = UINT16_MAX. Therefore,
79   		 * C = UINT16_MAX * P = UINT16_MAX / P_INVERSE.
80   		 */
81   		enum { P_CEIL = UINT16_MAX / P_INVERSE };
82   		int8_t level = SKIPLIST_LEVEL_MIN;
83   	
(1) Event dont_call: "random" should not be used for security-related applications, because linear congruential algorithms are too easy to break.
(2) Event remediation: Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows.
84   		while ((uint16_t) (random()) < P_CEIL)
85   			level++;
86   	
87   		if (level < SKIPLIST_LEVEL_MAX)
88   			return level;
89   	
90   		return SKIPLIST_LEVEL_MAX;
91   	}
92   	
93   	static struct skiplist_node *
94   	skiplist_node_next(const struct skiplist_node *node)
95   	{
96   		const struct skiplist_node *n = node;
97   		do {
98   			n = n->forward[SKIPLIST_LEVEL_MIN];
99   		} while (n && n->refcount == 0);
100  		return (struct skiplist_node *)n;
101  	}
102  	
103  	/*
104  	 * Create a new level @level node with value @value. The node should eventually
105  	 * be destroyed with @skiplist_node_destroy.
106  	 *
107  	 * return: a new node on success and NULL otherwise.
108  	 */
109  	static struct skiplist_node *
110  	skiplist_node_new(const int8_t level, const char *key, const void *value)
111  	{
112  		struct skiplist_node *new_node = (struct skiplist_node *)
113  		    (malloc(sizeof(struct skiplist_node)));
114  	
115  		if (!new_node)
116  			return NULL;
117  	
118  		new_node->value = (void *)value;
119  		new_node->key = key;
120  		new_node->level = level;
121  		new_node->refcount = 1;
122  		qb_list_init(&new_node->notifier_head);
123  	
124  		/* A level 0 node still needs to hold 1 forward pointer, etc.;
125  		   instead of "level + 1", we need to capture whole possible
126  		   width because of forward-member-resilience-upon-entry-removal
127  		   arrangment based on takeover-and-repoint. */
128  		new_node->forward = (struct skiplist_node **)
129  		    (calloc(SKIPLIST_LEVEL_MAX + 1, sizeof(struct skiplist_node *)));
130  	
131  		if (new_node->forward == NULL) {
132  			free(new_node);
133  			return NULL;
134  		}
135  	
136  		return new_node;
137  	}
138  	
139  	static struct skiplist_node *
140  	skiplist_header_node_new(void)
141  	{
142  		return skiplist_node_new(SKIPLIST_LEVEL_MAX, NULL, NULL);
143  	}
144  	
145  	/* An operation to perform after comparing a user value or search with a
146  	 * node's value
147  	 */
148  	typedef enum {
149  		OP_GOTO_NEXT_LEVEL,
150  		OP_GOTO_NEXT_NODE,
151  		OP_FINISH,
152  	} op_t;
153  	
154  	static op_t
155  	op_search(const struct skiplist *list,
156  		  const struct skiplist_node *fwd_node, const void *search)
157  	{
158  		int32_t cmp;
159  	
160  		if (!fwd_node)
161  			return OP_GOTO_NEXT_LEVEL;
162  	
163  		cmp = strcmp(fwd_node->key, search);
164  		if (cmp < 0) {
165  			return OP_GOTO_NEXT_NODE;
166  		} else if (cmp == 0) {
167  			return OP_FINISH;
168  		}
169  	
170  		return OP_GOTO_NEXT_LEVEL;
171  	}
172  	
173  	static struct skiplist_node *
174  	skiplist_lookup(struct skiplist *list, const char *key)
175  	{
176  		struct skiplist_node *cur_node = list->header;
177  		int8_t level = list->level;
178  	
179  		while (level >= SKIPLIST_LEVEL_MIN) {
180  			struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
181  	
182  			switch (op_search(list, fwd_node, key)) {
183  			case OP_FINISH:
184  				return fwd_node;
185  			case OP_GOTO_NEXT_NODE:
186  				cur_node = fwd_node;
187  				break;
188  			case OP_GOTO_NEXT_LEVEL:
189  				level--;
190  			}
191  		}
192  	
193  		return NULL;
194  	}
195  	
196  	static void
197  	skiplist_notify(struct skiplist *l, struct skiplist_node *n,
198  			uint32_t event, char *key, void *old_value, void *value)
199  	{
200  		struct qb_list_head *list;
201  		struct qb_map_notifier *tn;
202  	
203  		/* node callbacks
204  		 */
205  		qb_list_for_each(list, &n->notifier_head) {
206  			tn = qb_list_entry(list, struct qb_map_notifier, list);
207  	
208  			if (tn->events & event) {
209  				tn->callback(event, key, old_value, value,
210  					     tn->user_data);
211  			}
212  		}
213  		/* global callbacks
214  		 */
215  		qb_list_for_each(list, &l->header->notifier_head) {
216  			tn = qb_list_entry(list, struct qb_map_notifier, list);
217  	
218  			if (tn->events & event) {
219  				tn->callback(event, key, old_value, value,
220  					     tn->user_data);
221  			}
222  			if (((event & QB_MAP_NOTIFY_DELETED) ||
223  			     (event & QB_MAP_NOTIFY_REPLACED)) &&
224  			    (tn->events & QB_MAP_NOTIFY_FREE)) {
225  				tn->callback(QB_MAP_NOTIFY_FREE, (char *)key,
226  					     old_value, value, tn->user_data);
227  			}
228  		}
229  	
230  	}
231  	
232  	static void
233  	skiplist_node_destroy(struct skiplist_node *node, struct skiplist *list)
234  	{
235  		struct qb_list_head *pos;
236  		struct qb_list_head *next;
237  		struct qb_map_notifier *tn;
238  	
239  		skiplist_notify(list, node,
240  				QB_MAP_NOTIFY_DELETED,
241  				(char *)node->key, node->value, NULL);
242  	
243  		qb_list_for_each_safe(pos, next, &node->notifier_head) {
244  			tn = qb_list_entry(pos, struct qb_map_notifier, list);
245  			qb_list_del(&tn->list);
246  			free(tn);
247  		}
248  	
249  		if (node->level >= SKIPLIST_LEVEL_MIN
250  		    || list->level < SKIPLIST_LEVEL_MIN) {
251  			free(node->forward);
252  		}
253  		free(node);
254  	}
255  	
256  	static void
257  	skiplist_node_deref(struct skiplist_node *node, struct skiplist *list)
258  	{
259  		node->refcount--;
260  		if (node->refcount == 0) {
261  			skiplist_node_destroy(node, list);
262  		}
263  	}
264  	
265  	static int32_t
266  	skiplist_notify_add(qb_map_t * m, const char *key,
267  			    qb_map_notify_fn fn, int32_t events, void *user_data)
268  	{
269  		struct skiplist *t = (struct skiplist *)m;
270  		struct qb_map_notifier *f;
271  		struct skiplist_node *n;
272  		struct qb_list_head *list;
273  		int add_to_tail = QB_FALSE;
274  	
275  		if (key) {
276  			n = skiplist_lookup(t, key);
277  		} else {
278  			n = t->header;
279  		}
280  		if (events & QB_MAP_NOTIFY_FREE) {
281  			add_to_tail = QB_TRUE;
282  		}
283  		if (n) {
284  			qb_list_for_each(list, &n->notifier_head) {
285  				f = qb_list_entry(list, struct qb_map_notifier, list);
286  	
287  				if (events & QB_MAP_NOTIFY_FREE &&
288  				    f->events == events) {
289  					/* only one free notifier */
290  					return -EEXIST;
291  				}
292  				if (f->events == events &&
293  				    f->callback == fn &&
294  				    f->user_data == user_data) {
295  					return -EEXIST;
296  				}
297  			}
298  	
299  			f = malloc(sizeof(struct qb_map_notifier));
300  			if (f == NULL) {
301  				return -errno;
302  			}
303  			f->events = events;
304  			f->user_data = user_data;
305  			f->callback = fn;
306  			qb_list_init(&f->list);
307  			if (add_to_tail) {
308  				qb_list_add_tail(&f->list, &n->notifier_head);
309  			} else {
310  				qb_list_add(&f->list, &n->notifier_head);
311  			}
312  			return 0;
313  		}
314  		return -EINVAL;
315  	}
316  	
317  	static int32_t
318  	skiplist_notify_del(qb_map_t * m, const char *key,
319  			    qb_map_notify_fn fn, int32_t events,
320  			    int32_t cmp_userdata, void *user_data)
321  	{
322  		struct skiplist *t = (struct skiplist *)m;
323  		struct skiplist_node *n;
324  		struct qb_map_notifier *f;
325  		struct qb_list_head *head = NULL;
326  		struct qb_list_head *list;
327  		struct qb_list_head *next;
328  		int32_t found = QB_FALSE;
329  	
330  		if (key) {
331  			n = skiplist_lookup(t, key);
332  			if (n) {
333  				head = &n->notifier_head;
334  			}
335  		} else {
336  			head = &t->header->notifier_head;
337  		}
338  		if (head == NULL) {
339  			return -ENOENT;
340  		}
341  		qb_list_for_each_safe(list, next, head) {
342  			f = qb_list_entry(list, struct qb_map_notifier, list);
343  	
344  			if (f->events == events && f->callback == fn) {
345  				if (cmp_userdata && (f->user_data == user_data)) {
346  					found = QB_TRUE;
347  					qb_list_del(&f->list);
348  					free(f);
349  				} else if (!cmp_userdata) {
350  					found = QB_TRUE;
351  					qb_list_del(&f->list);
352  					free(f);
353  				}
354  			}
355  		}
356  		if (found) {
357  			return 0;
358  		} else {
359  			return -ENOENT;
360  		}
361  	}
362  	
363  	static void
364  	skiplist_destroy(struct qb_map *map)
365  	{
366  		struct skiplist *list = (struct skiplist *)map;
367  		struct skiplist_node *cur_node;
368  		struct skiplist_node *fwd_node;
369  	
370  		list->level = SKIPLIST_LEVEL_MIN - 1;  /* indicate teardown */
371  		for (cur_node = skiplist_node_next(list->header);
372  		     cur_node; cur_node = fwd_node) {
373  			fwd_node = skiplist_node_next(cur_node);
374  			skiplist_node_destroy(cur_node, list);
375  		}
376  		skiplist_node_destroy(list->header, list);
377  		free(list);
378  	}
379  	
380  	static void
381  	skiplist_put(struct qb_map *map, const char *key, const void *value)
382  	{
383  		struct skiplist *list = (struct skiplist *)map;
384  		struct skiplist_node *new_node;
385  		int8_t level = list->level;
386  		skiplist_update_t update;
387  		int8_t update_level;
388  		int8_t new_node_level;
389  		struct skiplist_node *cur_node = list->header;
390  		char *old_k;
391  		char *old_v;
392  	
393  		while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
394  			struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
395  	
396  			switch (op_search(list, fwd_node, key)) {
397  			case OP_FINISH:
398  				old_k = (char *)fwd_node->key;
399  				old_v = (char *)fwd_node->value;
400  				fwd_node->value = (void *)value;
401  				fwd_node->key = (void *)key;
402  				skiplist_notify(list, fwd_node,
403  						QB_MAP_NOTIFY_REPLACED,
404  						old_k, old_v, fwd_node->value);
405  				return;
406  	
407  			case OP_GOTO_NEXT_NODE:
408  				cur_node = fwd_node;
409  				break;
410  			case OP_GOTO_NEXT_LEVEL:
411  				level--;
412  			}
413  	
414  			update[(size_t)update_level] = cur_node;
415  		}
416  	
417  		new_node_level = skiplist_level_generate();
418  	
419  		if (new_node_level > list->level) {
420  			for (level = list->level + 1; level <= new_node_level; level++)
421  				update[(size_t)level] = list->header;
422  	
423  			list->level = new_node_level;
424  		}
425  	
426  		new_node = skiplist_node_new(new_node_level, key, value);
427  	
428  		assert(new_node != NULL);
429  		skiplist_notify(list, new_node,
430  				QB_MAP_NOTIFY_INSERTED,
431  				(char*)new_node->key, NULL, new_node->value);
432  	
433  		/* Drop @new_node into @list. */
434  		for (level = SKIPLIST_LEVEL_MIN; level <= new_node_level; level++) {
435  			new_node->forward[(size_t)level] = update[(size_t)level]->forward[(size_t)level];
436  			update[(size_t)level]->forward[(size_t)level] = new_node;
437  		}
438  	
439  		list->length++;
440  	}
441  	
442  	static int32_t
443  	skiplist_rm(struct qb_map *map, const char *key)
444  	{
445  		struct skiplist *list = (struct skiplist *)map;
446  		struct skiplist_node *found_node;
447  		struct skiplist_node *cur_node = list->header;
448  		int8_t level = list->level;
449  		int8_t update_level;
450  		skiplist_update_t update;
451  	
452  		while ((update_level = level) >= SKIPLIST_LEVEL_MIN) {
453  			struct skiplist_node *fwd_node = cur_node->forward[(size_t)level];
454  	
455  			switch (op_search(list, fwd_node, key)) {
456  			case OP_GOTO_NEXT_NODE:
457  				cur_node = fwd_node;
458  				break;
459  			case OP_GOTO_NEXT_LEVEL:
460  			default:
461  				level--;
462  				break;
463  			}
464  	
465  			update[(size_t)update_level] = cur_node;
466  		}
467  	
468  		/* The immediate forward node should be the matching node... */
469  		found_node = skiplist_node_next(cur_node);
470  	
471  		/* ...unless we're at the end of the list or the value doesn't exist. */
472  		if (!found_node || strcmp(found_node->key, key) != 0) {
473  			return QB_FALSE;
474  		}
475  	
476  		/* Splice found_node out of list. */
477  		for (level = SKIPLIST_LEVEL_MIN; level <= list->level; level++) {
478  			if (update[level]->forward[level] == found_node) {
479  				update[(size_t)level]->forward[(size_t)level] =
480  					found_node->forward[(size_t)level];
481  			}
482  		}
483  	
484  		/* If @found_node is referenced more than once, it means that it is
485  		   currently positioned with one or more iterators, therefore it's
486  		   likely that @qb_map_iter_next() will be called at least once so
487  		   as to progress pass this @found_node.  The problem is, original
488  		   @found_node->forward may have become referencing successfully
489  		   destroyed original successor by the time the progress of such
490  		   iterator(s) resumes, possibly causing use-after-free in
491  		   @skiplist_node_next().
492  	
493  		   To solve this, we will grab @cur_node->forward, which has just
494  		   been updated accordingly in the above statement, copying it
495  		   to @found_node->forward, and repointing @cur_node->forward to
496  		   point to @found_node's copy (freeing its original list first).
497  		   To prevent freeing the pointed memory behind @cur_node's
498  		   back from the @found_node's context, we use the fact that the
499  		   iterator can only advance to the next node, without re-examination
500  		   of the current one, hence we can afford to abuse @found_node->value
501  		   as a flag field when set to our private "special" value that under
502  		   no normal circumstance can appear (for being link-time singleton).
503  	
504  		   In addition, we have to special-case the beginning of the list
505  		   (header) preceding @found_node, which can be distinguished with
506  		   NULL being used as a key (second allowing condition below). */
507  		if (found_node->refcount > 1 || cur_node->key == NULL) {
508  			for (level = SKIPLIST_LEVEL_MIN; level <= found_node->level; level++) {
509  				found_node->forward[level] = cur_node->forward[level];
510  			}
511  			found_node->level = SKIPLIST_LEVEL_MIN - 1;  /* no "forward" drop */
512  			free(cur_node->forward);
513  			cur_node->forward = found_node->forward;
514  		}
515  		skiplist_node_deref(found_node, list);
516  	
517  		/* Remove unused levels from @list -- stop removing levels as soon as a
518  		 * used level is found. Unused levels can occur if @found_node had the
519  		 * highest level.
520  		 */
521  		for (level = list->level; level >= SKIPLIST_LEVEL_MIN; level--) {
522  			if (list->header->forward[(size_t)level])
523  				break;
524  	
525  			list->level--;
526  		}
527  	
528  		list->length--;
529  	
530  		return QB_TRUE;
531  	}
532  	
533  	static void *
534  	skiplist_get(struct qb_map *map, const char *key)
535  	{
536  		struct skiplist *list = (struct skiplist *)map;
537  		struct skiplist_node *n = skiplist_lookup(list, key);
538  		if (n) {
539  			return n->value;
540  		}
541  	
542  		return NULL;
543  	}
544  	
545  	static qb_map_iter_t *
546  	skiplist_iter_create(struct qb_map *map, const char *prefix)
547  	{
548  		struct skiplist_iter *i = malloc(sizeof(struct skiplist_iter));
549  		struct skiplist *list = (struct skiplist *)map;
550  		if (i == NULL) {
551  			return NULL;
552  		}
553  		i->i.m = map;
554  		i->n = list->header;
555  		i->n->refcount++;
556  		return (qb_map_iter_t *) i;
557  	}
558  	
559  	static const char *
560  	skiplist_iter_next(qb_map_iter_t * i, void **value)
561  	{
562  		struct skiplist_iter *si = (struct skiplist_iter *)i;
563  		struct skiplist_node *p = si->n;
564  	
565  		if (p == NULL) {
566  			return NULL;
567  		}
568  		si->n = skiplist_node_next(p);
569  		if (si->n == NULL) {
570  			skiplist_node_deref(p, (struct skiplist *)i->m);
571  			return NULL;
572  		}
573  		si->n->refcount++;
574  		skiplist_node_deref(p, (struct skiplist *)i->m);
575  		*value = si->n->value;
576  		return si->n->key;
577  	}
578  	
579  	static void
580  	skiplist_iter_free(qb_map_iter_t * i)
581  	{
582  		free(i);
583  	}
584  	
585  	static size_t
586  	skiplist_count_get(struct qb_map *map)
587  	{
588  		struct skiplist *list = (struct skiplist *)map;
589  		return list->length;
590  	}
591  	
592  	qb_map_t *
593  	qb_skiplist_create(void)
594  	{
595  		struct skiplist *sl = malloc(sizeof(struct skiplist));
596  		if (sl == NULL) {
597  			return NULL;
598  		}
599  	
600  		srand(time(NULL));
601  	
602  		sl->map.put = skiplist_put;
603  		sl->map.get = skiplist_get;
604  		sl->map.rm = skiplist_rm;
605  		sl->map.count_get = skiplist_count_get;
606  		sl->map.iter_create = skiplist_iter_create;
607  		sl->map.iter_next = skiplist_iter_next;
608  		sl->map.iter_free = skiplist_iter_free;
609  		sl->map.destroy = skiplist_destroy;
610  		sl->map.notify_add = skiplist_notify_add;
611  		sl->map.notify_del = skiplist_notify_del;
612  		sl->level = SKIPLIST_LEVEL_MIN;
613  		sl->length = 0;
614  		sl->header = skiplist_header_node_new();
615  	
616  		return (qb_map_t *) sl;
617  	}
618