File: cookie_cache.c

package info (click to toggle)
rtpengine 13.5.1.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,676 kB
  • sloc: ansic: 86,775; perl: 59,422; python: 3,193; sh: 1,037; makefile: 687; asm: 211
file content (106 lines) | stat: -rw-r--r-- 3,056 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "cookie_cache.h"

#include <time.h>
#include <glib.h>

#include "compat.h"
#include "helpers.h"
#include "poller.h"
#include "str.h"

INLINE void cookie_cache_state_init(struct cookie_cache_state *s) {
	bencode_buffer_init(&s->buffer);
	s->in_use = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal);
	s->cookies = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal);
}
INLINE void cookie_cache_state_cleanup(struct cookie_cache_state *s) {
	g_hash_table_destroy(s->cookies);
	g_hash_table_destroy(s->in_use);
	bencode_buffer_free(&s->buffer);
}

void cookie_cache_init(struct cookie_cache *c) {
	cookie_cache_state_init(&c->current);
	cookie_cache_state_init(&c->old);
	c->swap_time_us = rtpe_now;
	mutex_init(&c->lock);
	cond_init(&c->cond);
}

/* lock must be held */
static void __cookie_cache_check_swap(struct cookie_cache *c) {
	if (rtpe_now - c->swap_time_us >= 30000000LL) {
		g_hash_table_remove_all(c->old.cookies);
		bencode_buffer_free(&c->old.buffer);
		swap_ptrs(&c->old.cookies, &c->current.cookies);
		c->old.buffer = c->current.buffer;
		bencode_buffer_init(&c->current.buffer);
		c->swap_time_us = rtpe_now;
	}
}

static cache_entry *__cache_entry_dup(struct cookie_cache_state *c, const cache_entry *s) {
	if (!s)
		return NULL;
	cache_entry *r;
	r = bencode_buffer_alloc(&c->buffer, sizeof(*r));
	r->reply = bencode_str_strdup(&c->buffer, &s->reply);
	r->command = s->command;
	r->callid = bencode_str_strdup(&c->buffer, &s->callid);
	return r;
}

cache_entry *cookie_cache_lookup(struct cookie_cache *c, const str *s) {
	cache_entry *ret;

	LOCK(&c->lock);

	__cookie_cache_check_swap(c);

restart:
	ret = g_hash_table_lookup(c->current.cookies, s);
	if (!ret)
		ret = g_hash_table_lookup(c->old.cookies, s);
	if (ret) {
		ret = cache_entry_dup(ret);
		return ret;
	}

	// is it being worked on right now by another thread?
	void *p = g_hash_table_lookup(c->current.in_use, s);
	if (!p)
		p = g_hash_table_lookup(c->old.in_use, s);
	if (p) {
		cond_wait(&c->cond, &c->lock);
		goto restart;
	}

	// caller is required to call cookie_cache_insert or cookie_cache_remove
	// before `s` runs out of scope
	g_hash_table_replace(c->current.in_use, (void *) s, (void *) 0x1);
	return NULL;
}

void cookie_cache_insert(struct cookie_cache *c, const str *s, const struct cache_entry *entry) {
	LOCK(&c->lock);
	g_hash_table_remove(c->current.in_use, s);
	g_hash_table_remove(c->old.in_use, s);
	g_hash_table_replace(c->current.cookies, bencode_str_str_dup(&c->current.buffer, s),
			__cache_entry_dup(&c->current, entry));
	g_hash_table_remove(c->old.cookies, s);
	cond_broadcast(&c->cond);
}

void cookie_cache_remove(struct cookie_cache *c, const str *s) {
	LOCK(&c->lock);
	g_hash_table_remove(c->current.in_use, s);
	g_hash_table_remove(c->old.in_use, s);
	g_hash_table_remove(c->current.cookies, s);
	g_hash_table_remove(c->old.cookies, s);
	cond_broadcast(&c->cond);
}

void cookie_cache_cleanup(struct cookie_cache *c) {
	cookie_cache_state_cleanup(&c->current);
	cookie_cache_state_cleanup(&c->old);
}