diff options
author | Dirk Engling <erdgeist@erdgeist.org> | 2021-04-19 22:33:23 +0200 |
---|---|---|
committer | Dirk Engling <erdgeist@erdgeist.org> | 2021-04-19 22:33:23 +0200 |
commit | 102ba9075b8df32627f38074a293d804e04139ba (patch) | |
tree | cce73c37a043055e37a6a52fc2c978110ebdaff3 /ot_accesslist.c | |
parent | fde79836e6ebb339f67f99768b5b75dde619779e (diff) |
Make accesslist reload thread safe. The last commit actually would make a free possible while another thread was bsearching that memory
Diffstat (limited to 'ot_accesslist.c')
-rw-r--r-- | ot_accesslist.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/ot_accesslist.c b/ot_accesslist.c index 12bd29e..2e3778f 100644 --- a/ot_accesslist.c +++ b/ot_accesslist.c | |||
@@ -25,19 +25,25 @@ | |||
25 | /* GLOBAL VARIABLES */ | 25 | /* GLOBAL VARIABLES */ |
26 | #ifdef WANT_ACCESSLIST | 26 | #ifdef WANT_ACCESSLIST |
27 | char *g_accesslist_filename; | 27 | char *g_accesslist_filename; |
28 | static ot_hash *g_accesslist; | ||
29 | static size_t g_accesslist_size; | ||
30 | static pthread_mutex_t g_accesslist_mutex; | 28 | static pthread_mutex_t g_accesslist_mutex; |
31 | 29 | ||
30 | typedef struct { | ||
31 | ot_hash *list; | ||
32 | size_t size; | ||
33 | } ot_accesslist; | ||
34 | ot_accesslist * g_accesslist = NULL; | ||
35 | ot_accesslist * g_accesslist_old = NULL; | ||
36 | |||
32 | static int vector_compare_hash(const void *hash1, const void *hash2 ) { | 37 | static int vector_compare_hash(const void *hash1, const void *hash2 ) { |
33 | return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); | 38 | return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); |
34 | } | 39 | } |
35 | 40 | ||
36 | /* Read initial access list */ | 41 | /* Read initial access list */ |
37 | static void accesslist_readfile( void ) { | 42 | static void accesslist_readfile( void ) { |
38 | ot_hash *info_hash, *accesslist_new = NULL, *accesslist_old; | 43 | ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); |
39 | char *map, *map_end, *read_offs; | 44 | ot_hash *info_hash; |
40 | size_t maplen; | 45 | const char *map, *map_end, *read_offs; |
46 | size_t maplen; | ||
41 | 47 | ||
42 | if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { | 48 | if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { |
43 | char *wd = getcwd( NULL, 0 ); | 49 | char *wd = getcwd( NULL, 0 ); |
@@ -48,9 +54,11 @@ static void accesslist_readfile( void ) { | |||
48 | 54 | ||
49 | /* You need at least 41 bytes to pass an info_hash, make enough room | 55 | /* You need at least 41 bytes to pass an info_hash, make enough room |
50 | for the maximum amount of them */ | 56 | for the maximum amount of them */ |
51 | info_hash = accesslist_new = malloc( ( maplen / 41 ) * 20 ); | 57 | accesslist_new->size = 0; |
58 | info_hash = accesslist_new->list = malloc( ( maplen / 41 ) * 20 ); | ||
52 | if( !accesslist_new ) { | 59 | if( !accesslist_new ) { |
53 | fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); | 60 | fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); |
61 | free(accesslist_new); | ||
54 | return; | 62 | return; |
55 | } | 63 | } |
56 | 64 | ||
@@ -81,28 +89,33 @@ static void accesslist_readfile( void ) { | |||
81 | while( read_offs <= map_end && *(read_offs++) != '\n' ); | 89 | while( read_offs <= map_end && *(read_offs++) != '\n' ); |
82 | } | 90 | } |
83 | #ifdef _DEBUG | 91 | #ifdef _DEBUG |
84 | fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new) ); | 92 | fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list) ); |
85 | #endif | 93 | #endif |
86 | 94 | ||
87 | mmap_unmap( map, maplen); | 95 | mmap_unmap( map, maplen); |
88 | 96 | ||
89 | qsort( accesslist_new, info_hash - accesslist_new, sizeof( *info_hash ), vector_compare_hash ); | 97 | qsort( accesslist_new->list, info_hash - accesslist_new->list, sizeof( *info_hash ), vector_compare_hash ); |
98 | accesslist_new->size = info_hash - accesslist_new->list; | ||
90 | 99 | ||
91 | /* Now exchange the accesslist vector in the least race condition prone way */ | 100 | /* Now exchange the accesslist vector in the least race condition prone way */ |
92 | pthread_mutex_lock(&g_accesslist_mutex); | 101 | pthread_mutex_lock(&g_accesslist_mutex); |
93 | 102 | ||
94 | accesslist_old = g_accesslist; /* Keep a copy for later free */ | 103 | if (g_accesslist_old) { |
95 | g_accesslist_size = 0; /* Set size to 0 to prevent clients from searching through uninitialised memory */ | 104 | free(g_accesslist_old->list); |
96 | g_accesslist = accesslist_new; /* Only now set a new list */ | 105 | free(g_accesslist_old); |
97 | g_accesslist_size = info_hash - accesslist_new; /* And finally store it's size */ | 106 | } |
98 | free(g_accesslist_old); /* If new list is active, the old one can be destroyed */ | 107 | |
108 | g_accesslist_old = g_accesslist; /* Keep a copy for later free */ | ||
109 | g_accesslist = accesslist_new; /* Only now set a new list */ | ||
110 | |||
99 | pthread_mutex_unlock(&g_accesslist_mutex); | 111 | pthread_mutex_unlock(&g_accesslist_mutex); |
100 | } | 112 | } |
101 | 113 | ||
102 | int accesslist_hashisvalid( ot_hash hash ) { | 114 | int accesslist_hashisvalid( ot_hash hash ) { |
103 | void *exactmatch; | 115 | /* Get working copy of current access list */ |
116 | ot_accesslist * accesslist = g_accesslist; | ||
104 | 117 | ||
105 | exactmatch = bsearch( hash, g_accesslist, g_accesslist_size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); | 118 | void * exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); |
106 | 119 | ||
107 | #ifdef WANT_ACCESSLIST_BLACK | 120 | #ifdef WANT_ACCESSLIST_BLACK |
108 | return exactmatch == NULL; | 121 | return exactmatch == NULL; |
@@ -140,9 +153,18 @@ void accesslist_init( ) { | |||
140 | void accesslist_deinit( void ) { | 153 | void accesslist_deinit( void ) { |
141 | pthread_cancel( thread_id ); | 154 | pthread_cancel( thread_id ); |
142 | pthread_mutex_destroy(&g_accesslist_mutex); | 155 | pthread_mutex_destroy(&g_accesslist_mutex); |
143 | free( g_accesslist ); | 156 | |
144 | g_accesslist = 0; | 157 | if (g_accesslist_old) { |
145 | g_accesslist_size = 0; | 158 | free(g_accesslist_old->list); |
159 | free(g_accesslist_old); | ||
160 | g_accesslist_old = 0; | ||
161 | } | ||
162 | |||
163 | if (g_accesslist) { | ||
164 | free(g_accesslist->list); | ||
165 | free(g_accesslist); | ||
166 | g_accesslist = 0; | ||
167 | } | ||
146 | } | 168 | } |
147 | #endif | 169 | #endif |
148 | 170 | ||