diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | opentracker.c | 12 | ||||
| -rw-r--r-- | opentracker.conf.sample | 37 | ||||
| -rw-r--r-- | ot_accesslist.c | 273 | ||||
| -rw-r--r-- | ot_accesslist.h | 8 | ||||
| -rw-r--r-- | ot_mutex.h | 6 | ||||
| -rw-r--r-- | ot_stats.h | 6 | ||||
| -rw-r--r-- | trackerlogic.h | 5 |
8 files changed, 298 insertions, 50 deletions
| @@ -24,6 +24,7 @@ STRIP?=strip | |||
| 24 | 24 | ||
| 25 | #FEATURES+=-DWANT_ACCESSLIST_BLACK | 25 | #FEATURES+=-DWANT_ACCESSLIST_BLACK |
| 26 | #FEATURES+=-DWANT_ACCESSLIST_WHITE | 26 | #FEATURES+=-DWANT_ACCESSLIST_WHITE |
| 27 | #FEATURES+=-DWANT_DYNAMIC_ACCESSLIST | ||
| 27 | 28 | ||
| 28 | #FEATURES+=-DWANT_SYNC_LIVE | 29 | #FEATURES+=-DWANT_SYNC_LIVE |
| 29 | #FEATURES+=-DWANT_IP_FROM_QUERY_STRING | 30 | #FEATURES+=-DWANT_IP_FROM_QUERY_STRING |
diff --git a/opentracker.c b/opentracker.c index a5ba7d3..b6d2bb9 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -135,8 +135,8 @@ static void help( char *name ) { | |||
| 135 | } | 135 | } |
| 136 | #undef HELPLINE | 136 | #undef HELPLINE |
| 137 | 137 | ||
| 138 | static size_t header_complete( char * request, ssize_t byte_count ) { | 138 | static ssize_t header_complete( char * request, ssize_t byte_count ) { |
| 139 | int i = 0, state = 0; | 139 | ssize_t i = 0, state = 0; |
| 140 | 140 | ||
| 141 | for( i=1; i < byte_count; i+=2 ) | 141 | for( i=1; i < byte_count; i+=2 ) |
| 142 | if( request[i] <= 13 ) { | 142 | if( request[i] <= 13 ) { |
| @@ -184,7 +184,7 @@ static void handle_read( const int64 sock, struct ot_workstruct *ws ) { | |||
| 184 | ws->request_size = byte_count; | 184 | ws->request_size = byte_count; |
| 185 | http_handle_request( sock, ws ); | 185 | http_handle_request( sock, ws ); |
| 186 | } else | 186 | } else |
| 187 | array_catb( &cookie->request, ws->inbuf, byte_count ); | 187 | array_catb( &cookie->request, ws->inbuf, (size_t)byte_count ); |
| 188 | return; | 188 | return; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| @@ -463,6 +463,12 @@ int parse_configfile( char * config_filename ) { | |||
| 463 | } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) { | 463 | } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) { |
| 464 | set_config_option( &g_accesslist_filename, p+17 ); | 464 | set_config_option( &g_accesslist_filename, p+17 ); |
| 465 | #endif | 465 | #endif |
| 466 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 467 | } else if(!byte_diff(p, 15, "access.fifo_add" ) && isspace(p[15])) { | ||
| 468 | set_config_option( &g_accesslist_pipe_add, p+16 ); | ||
| 469 | } else if(!byte_diff(p, 18, "access.fifo_delete" ) && isspace(p[18])) { | ||
| 470 | set_config_option( &g_accesslist_pipe_delete, p+19 ); | ||
| 471 | #endif | ||
| 466 | #ifdef WANT_RESTRICT_STATS | 472 | #ifdef WANT_RESTRICT_STATS |
| 467 | } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) { | 473 | } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) { |
| 468 | if( !scan_ip6( p+13, tmpip )) goto parse_error; | 474 | if( !scan_ip6( p+13, tmpip )) goto parse_error; |
diff --git a/opentracker.conf.sample b/opentracker.conf.sample index db45122..55c2828 100644 --- a/opentracker.conf.sample +++ b/opentracker.conf.sample | |||
| @@ -44,6 +44,43 @@ | |||
| 44 | # listing, so choose one of those options at compile time. File format | 44 | # listing, so choose one of those options at compile time. File format |
| 45 | # is straight forward: "<hex info hash>\n<hex info hash>\n..." | 45 | # is straight forward: "<hex info hash>\n<hex info hash>\n..." |
| 46 | # | 46 | # |
| 47 | # IIa) You can enable dynamic changesets to accesslists by enabling | ||
| 48 | # WANT_DYNAMIC_ACCESSLIST. | ||
| 49 | # | ||
| 50 | # The suggested way to work with dynamic changeset lists is to keep a | ||
| 51 | # main accesslist file that is loaded when opentracker (re)starts and | ||
| 52 | # reloaded infrequently (hourly or daily). | ||
| 53 | # | ||
| 54 | # All changes to the accesslist (e.g. from a web frontend) should be | ||
| 55 | # both appended to or removed from that file and sent to opentracker. By | ||
| 56 | # keeping dynamic changeset lists, you can avoid reloading huge | ||
| 57 | # accesslists whenever just a single entry is added or removed. | ||
| 58 | # | ||
| 59 | # Any info_hash (format see above) written to the fifo_add file will be | ||
| 60 | # kept on a dynamic add-changeset, removed from the dynamic | ||
| 61 | # delete-changeset and treated as if it was in the main accesslist file. | ||
| 62 | # The semantic of the respective dynamic changeset depends on whether | ||
| 63 | # WANT_ACCESSLIST_WHITE or WANT_ACCESSLIST_BLACK is enabled. | ||
| 64 | # | ||
| 65 | # access.fifo_add /var/run/opentracker/adder.fifo | ||
| 66 | # | ||
| 67 | # Any info_hash (format see above) written to the fifo_delete file will | ||
| 68 | # be kept on a dynamic delete-changeset, removed from the dynamic | ||
| 69 | # add-changeset and treated as if it was not in the main accesslist | ||
| 70 | # file. | ||
| 71 | # | ||
| 72 | # access.fifo_delete /var/run/opentracker/deleter.fifo | ||
| 73 | # | ||
| 74 | # If you reload the accesslist by sending SIGHUP to the tracker process, | ||
| 75 | # the dynamic lists are flushed, as opentracker assumes thoses lists are | ||
| 76 | # merged into the main accesslist. | ||
| 77 | # | ||
| 78 | # NOTE: While you can have multiple writers sending lines to the fifos, | ||
| 79 | # any writes larger than PIPE_BUF (see your limits.h, minimally 512 | ||
| 80 | # bytes but usually 4096) may be interleaved with data sent by other | ||
| 81 | # writers. This can lead to unparsable lines of info_hashes. | ||
| 82 | # | ||
| 83 | # IIb) | ||
| 47 | # If you do not want to grant anyone access to your stats, enable the | 84 | # If you do not want to grant anyone access to your stats, enable the |
| 48 | # WANT_RESTRICT_STATS option in Makefile and bless the ip addresses | 85 | # WANT_RESTRICT_STATS option in Makefile and bless the ip addresses |
| 49 | # allowed to fetch stats here. | 86 | # allowed to fetch stats here. |
diff --git a/ot_accesslist.c b/ot_accesslist.c index a3a2049..078cebd 100644 --- a/ot_accesslist.c +++ b/ot_accesslist.c | |||
| @@ -10,6 +10,11 @@ | |||
| 10 | #include <stdio.h> | 10 | #include <stdio.h> |
| 11 | #include <signal.h> | 11 | #include <signal.h> |
| 12 | #include <unistd.h> | 12 | #include <unistd.h> |
| 13 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 14 | #include <sys/types.h> | ||
| 15 | #include <sys/stat.h> | ||
| 16 | #include <errno.h> | ||
| 17 | #endif | ||
| 13 | 18 | ||
| 14 | /* Libowfat */ | 19 | /* Libowfat */ |
| 15 | #include "byte.h" | 20 | #include "byte.h" |
| @@ -24,23 +29,80 @@ | |||
| 24 | 29 | ||
| 25 | /* GLOBAL VARIABLES */ | 30 | /* GLOBAL VARIABLES */ |
| 26 | #ifdef WANT_ACCESSLIST | 31 | #ifdef WANT_ACCESSLIST |
| 27 | char *g_accesslist_filename; | 32 | char *g_accesslist_filename = NULL; |
| 33 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 34 | char *g_accesslist_pipe_add = NULL; | ||
| 35 | char *g_accesslist_pipe_delete = NULL; | ||
| 36 | #endif | ||
| 28 | static pthread_mutex_t g_accesslist_mutex; | 37 | static pthread_mutex_t g_accesslist_mutex; |
| 29 | 38 | ||
| 30 | typedef struct { | 39 | /* Accesslists are lock free linked lists. We can not make them locking, because every announce |
| 31 | ot_hash *list; | 40 | would try to acquire the mutex, making it the most contested mutex in the whole of opentracker, |
| 32 | size_t size; | 41 | basically creating a central performance choke point. |
| 33 | } ot_accesslist; | 42 | |
| 34 | ot_accesslist * g_accesslist = NULL; | 43 | The idea is that updating the list heads happens under the g_accesslist_mutex guard and is |
| 35 | ot_accesslist * g_accesslist_old = NULL; | 44 | done atomically, while consumers might potentially still hold pointers deeper inside the list. |
| 45 | |||
| 46 | Consumers (for now only via accesslist_hashisvalid) will always fetch the list head pointer | ||
| 47 | that is guaranteed to live for at least five minutes. This should be many orders of magnitudes | ||
| 48 | more than how long it will be needed by the bsearch done on the list. */ | ||
| 49 | struct ot_accesslist; | ||
| 50 | typedef struct ot_accesslist ot_accesslist; | ||
| 51 | struct ot_accesslist { | ||
| 52 | ot_hash *list; | ||
| 53 | size_t size; | ||
| 54 | ot_time base; | ||
| 55 | ot_accesslist *next; | ||
| 56 | }; | ||
| 57 | static ot_accesslist * g_accesslist = NULL; | ||
| 58 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 59 | static ot_accesslist * g_accesslist_add = NULL; | ||
| 60 | static ot_accesslist * g_accesslist_delete = NULL; | ||
| 61 | #endif | ||
| 36 | 62 | ||
| 63 | /* Helpers to work on access lists */ | ||
| 37 | static int vector_compare_hash(const void *hash1, const void *hash2 ) { | 64 | static int vector_compare_hash(const void *hash1, const void *hash2 ) { |
| 38 | return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); | 65 | return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); |
| 39 | } | 66 | } |
| 40 | 67 | ||
| 68 | static ot_accesslist * accesslist_free(ot_accesslist *accesslist) { | ||
| 69 | while (accesslist) { | ||
| 70 | ot_accesslist * this_accesslist = accesslist; | ||
| 71 | accesslist = this_accesslist->next; | ||
| 72 | free(this_accesslist->list); | ||
| 73 | free(this_accesslist); | ||
| 74 | } | ||
| 75 | return NULL; | ||
| 76 | } | ||
| 77 | |||
| 78 | static ot_accesslist * accesslist_make(ot_accesslist *next, size_t size) { | ||
| 79 | ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); | ||
| 80 | if (accesslist_new) { | ||
| 81 | accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL; | ||
| 82 | accesslist_new->size = size; | ||
| 83 | accesslist_new->base = g_now_minutes; | ||
| 84 | accesslist_new->next = next; | ||
| 85 | if (size && !accesslist_new->list) { | ||
| 86 | free(accesslist_new); | ||
| 87 | accesslist_new = NULL; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | return accesslist_new; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* This must be called with g_accesslist_mutex held. | ||
| 94 | This will never delete head, because that might still be in use. */ | ||
| 95 | static void accesslist_clean(ot_accesslist *accesslist) { | ||
| 96 | while (accesslist && accesslist->next) { | ||
| 97 | if (accesslist->next->base + 5 < g_now_minutes) | ||
| 98 | accesslist->next = accesslist_free(accesslist->next); | ||
| 99 | accesslist = accesslist->next; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 41 | /* Read initial access list */ | 103 | /* Read initial access list */ |
| 42 | static void accesslist_readfile( void ) { | 104 | static void accesslist_readfile( void ) { |
| 43 | ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); | 105 | ot_accesslist * accesslist_new; |
| 44 | ot_hash *info_hash; | 106 | ot_hash *info_hash; |
| 45 | const char *map, *map_end, *read_offs; | 107 | const char *map, *map_end, *read_offs; |
| 46 | size_t maplen; | 108 | size_t maplen; |
| @@ -54,14 +116,13 @@ static void accesslist_readfile( void ) { | |||
| 54 | 116 | ||
| 55 | /* You need at least 41 bytes to pass an info_hash, make enough room | 117 | /* You need at least 41 bytes to pass an info_hash, make enough room |
| 56 | for the maximum amount of them */ | 118 | for the maximum amount of them */ |
| 57 | accesslist_new->size = 0; | 119 | accesslist_new = accesslist_make(g_accesslist, maplen / 41); |
| 58 | info_hash = accesslist_new->list = malloc( ( maplen / 41 ) * 20 ); | 120 | if( !accesslist_new ) { |
| 59 | if( !accesslist_new->list ) { | ||
| 60 | fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); | 121 | fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); |
| 61 | mmap_unmap( map, maplen); | 122 | mmap_unmap( map, maplen); |
| 62 | free(accesslist_new); | ||
| 63 | return; | 123 | return; |
| 64 | } | 124 | } |
| 125 | info_hash = accesslist_new->list; | ||
| 65 | 126 | ||
| 66 | /* No use to scan if there's not enough room for another full info_hash */ | 127 | /* No use to scan if there's not enough room for another full info_hash */ |
| 67 | map_end = map + maplen - 40; | 128 | map_end = map + maplen - 40; |
| @@ -71,18 +132,18 @@ static void accesslist_readfile( void ) { | |||
| 71 | while( read_offs <= map_end ) { | 132 | while( read_offs <= map_end ) { |
| 72 | int i; | 133 | int i; |
| 73 | for( i=0; i<(int)sizeof(ot_hash); ++i ) { | 134 | for( i=0; i<(int)sizeof(ot_hash); ++i ) { |
| 74 | int eger1 = scan_fromhex( read_offs[ 2*i ] ); | 135 | int eger1 = scan_fromhex( (unsigned char)read_offs[ 2*i ] ); |
| 75 | int eger2 = scan_fromhex( read_offs[ 1 + 2*i ] ); | 136 | int eger2 = scan_fromhex( (unsigned char)read_offs[ 1 + 2*i ] ); |
| 76 | if( eger1 < 0 || eger2 < 0 ) | 137 | if( eger1 < 0 || eger2 < 0 ) |
| 77 | break; | 138 | break; |
| 78 | (*info_hash)[i] = eger1 * 16 + eger2; | 139 | (*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2); |
| 79 | } | 140 | } |
| 80 | 141 | ||
| 81 | if( i == sizeof(ot_hash) ) { | 142 | if( i == sizeof(ot_hash) ) { |
| 82 | read_offs += 40; | 143 | read_offs += 40; |
| 83 | 144 | ||
| 84 | /* Append accesslist to accesslist vector */ | 145 | /* Append accesslist to accesslist vector */ |
| 85 | if( read_offs == map_end || scan_fromhex( *read_offs ) < 0 ) | 146 | if( read_offs == map_end || scan_fromhex( (unsigned char)*read_offs ) < 0 ) |
| 86 | ++info_hash; | 147 | ++info_hash; |
| 87 | } | 148 | } |
| 88 | 149 | ||
| @@ -100,14 +161,19 @@ static void accesslist_readfile( void ) { | |||
| 100 | 161 | ||
| 101 | /* Now exchange the accesslist vector in the least race condition prone way */ | 162 | /* Now exchange the accesslist vector in the least race condition prone way */ |
| 102 | pthread_mutex_lock(&g_accesslist_mutex); | 163 | pthread_mutex_lock(&g_accesslist_mutex); |
| 164 | accesslist_new->next = g_accesslist; | ||
| 165 | g_accesslist = accesslist_new; /* Only now set a new list */ | ||
| 166 | |||
| 167 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 168 | /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists. | ||
| 169 | Insert empty ones at the list head */ | ||
| 170 | if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL) | ||
| 171 | g_accesslist_add = accesslist_new; | ||
| 172 | if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL) | ||
| 173 | g_accesslist_delete = accesslist_new; | ||
| 174 | #endif | ||
| 103 | 175 | ||
| 104 | if (g_accesslist_old) { | 176 | accesslist_clean(g_accesslist); |
| 105 | free(g_accesslist_old->list); | ||
| 106 | free(g_accesslist_old); | ||
| 107 | } | ||
| 108 | |||
| 109 | g_accesslist_old = g_accesslist; /* Keep a copy for later free */ | ||
| 110 | g_accesslist = accesslist_new; /* Only now set a new list */ | ||
| 111 | 177 | ||
| 112 | pthread_mutex_unlock(&g_accesslist_mutex); | 178 | pthread_mutex_unlock(&g_accesslist_mutex); |
| 113 | } | 179 | } |
| @@ -115,11 +181,25 @@ static void accesslist_readfile( void ) { | |||
| 115 | int accesslist_hashisvalid( ot_hash hash ) { | 181 | int accesslist_hashisvalid( ot_hash hash ) { |
| 116 | /* Get working copy of current access list */ | 182 | /* Get working copy of current access list */ |
| 117 | ot_accesslist * accesslist = g_accesslist; | 183 | ot_accesslist * accesslist = g_accesslist; |
| 118 | 184 | #ifdef WANT_DYNAMIC_ACCESSLIST | |
| 185 | ot_accesslist * accesslist_add, * accesslist_delete; | ||
| 186 | #endif | ||
| 119 | void * exactmatch = NULL; | 187 | void * exactmatch = NULL; |
| 120 | 188 | ||
| 121 | if (accesslist) | 189 | if (accesslist) |
| 122 | exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); | 190 | exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); |
| 191 | |||
| 192 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 193 | /* If we had no match on the main list, scan the list of dynamically added hashes */ | ||
| 194 | accesslist_add = g_accesslist_add; | ||
| 195 | if ((exactmatch == NULL) && accesslist_add) | ||
| 196 | exactmatch = bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); | ||
| 197 | |||
| 198 | /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */ | ||
| 199 | accesslist_delete = g_accesslist_delete; | ||
| 200 | if ((exactmatch != NULL) && accesslist_delete && bsearch( hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash )) | ||
| 201 | exactmatch = NULL; | ||
| 202 | #endif | ||
| 123 | 203 | ||
| 124 | #ifdef WANT_ACCESSLIST_BLACK | 204 | #ifdef WANT_ACCESSLIST_BLACK |
| 125 | return exactmatch == NULL; | 205 | return exactmatch == NULL; |
| @@ -138,6 +218,8 @@ static void * accesslist_worker( void * args ) { | |||
| 138 | (void)args; | 218 | (void)args; |
| 139 | 219 | ||
| 140 | while( 1 ) { | 220 | while( 1 ) { |
| 221 | if (!g_opentracker_running) | ||
| 222 | return NULL; | ||
| 141 | 223 | ||
| 142 | /* Initial attempt to read accesslist */ | 224 | /* Initial attempt to read accesslist */ |
| 143 | accesslist_readfile( ); | 225 | accesslist_readfile( ); |
| @@ -148,27 +230,144 @@ static void * accesslist_worker( void * args ) { | |||
| 148 | return NULL; | 230 | return NULL; |
| 149 | } | 231 | } |
| 150 | 232 | ||
| 233 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 234 | static pthread_t thread_adder_id, thread_deleter_id; | ||
| 235 | static void * accesslist_adddel_worker(char * fifoname, ot_accesslist ** adding_to, ot_accesslist ** removing_from) { | ||
| 236 | struct stat st; | ||
| 237 | |||
| 238 | if (!stat(fifoname, &st)) { | ||
| 239 | if (!S_ISFIFO(st.st_mode)) { | ||
| 240 | fprintf(stderr, "Error when starting dynamic accesslists: Found Non-FIFO file at %s.\nPlease remove it and restart opentracker.\n", fifoname); | ||
| 241 | return NULL; | ||
| 242 | } | ||
| 243 | } else { | ||
| 244 | int error = mkfifo(fifoname, 0755); | ||
| 245 | if (error && error != EEXIST) { | ||
| 246 | fprintf(stderr, "Error when starting dynamic accesslists: Couldn't create FIFO at %s, error: %s\n", fifoname, strerror(errno)); | ||
| 247 | return NULL; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | while (g_opentracker_running) { | ||
| 252 | FILE * fifo = fopen(fifoname, "r"); | ||
| 253 | char *line = NULL; | ||
| 254 | size_t linecap = 0; | ||
| 255 | ssize_t linelen; | ||
| 256 | |||
| 257 | if (!fifo) { | ||
| 258 | fprintf(stderr, "Error when reading dynamic accesslists: Couldn't open FIFO at %s, error: %s\n", fifoname, strerror(errno)); | ||
| 259 | return NULL; | ||
| 260 | } | ||
| 261 | |||
| 262 | while ((linelen = getline(&line, &linecap, fifo)) > 0) { | ||
| 263 | ot_hash info_hash; | ||
| 264 | int i; | ||
| 265 | |||
| 266 | printf("Got line %*s", (int)linelen, line); | ||
| 267 | /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" | ||
| 268 | If there's not enough characters for an info_hash in the line, skip it. */ | ||
| 269 | if (linelen < 41) | ||
| 270 | continue; | ||
| 271 | |||
| 272 | for( i=0; i<(int)sizeof(ot_hash); ++i ) { | ||
| 273 | int eger1 = scan_fromhex( (unsigned char)line[ 2*i ] ); | ||
| 274 | int eger2 = scan_fromhex( (unsigned char)line[ 1 + 2*i ] ); | ||
| 275 | if( eger1 < 0 || eger2 < 0 ) | ||
| 276 | break; | ||
| 277 | ((uint8_t*)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2); | ||
| 278 | } | ||
| 279 | printf("parsed info_hash %20s\n", info_hash); | ||
| 280 | if( i != sizeof(ot_hash) ) | ||
| 281 | continue; | ||
| 282 | |||
| 283 | /* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the | ||
| 284 | other worker threads from doing the same */ | ||
| 285 | pthread_mutex_lock(&g_accesslist_mutex); | ||
| 286 | |||
| 287 | /* If the info hash is in the removing_from list, create a new head without that entry */ | ||
| 288 | if (*removing_from && (*removing_from)->list) { | ||
| 289 | ot_hash * exactmatch = bsearch( info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); | ||
| 290 | if (exactmatch) { | ||
| 291 | ptrdiff_t off = exactmatch - (*removing_from)->list; | ||
| 292 | ot_accesslist * accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1); | ||
| 293 | if (accesslist_new) { | ||
| 294 | memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off); | ||
| 295 | memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1); | ||
| 296 | *removing_from = accesslist_new; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | accesslist_clean(*removing_from); | ||
| 301 | |||
| 302 | /* Simple case: there's no adding_to list yet, create one with one member */ | ||
| 303 | if (!*adding_to) { | ||
| 304 | *adding_to = accesslist_make(NULL, 1); | ||
| 305 | if (*adding_to) | ||
| 306 | memcpy((*adding_to)->list, info_hash, sizeof(ot_hash)); | ||
| 307 | } else { | ||
| 308 | int exactmatch = 0; | ||
| 309 | ot_hash * insert_point = binary_search( info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch ); | ||
| 310 | |||
| 311 | /* Only if the info hash is not in the adding_to list, create a new head with that entry */ | ||
| 312 | if (!exactmatch) { | ||
| 313 | ot_accesslist * accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1); | ||
| 314 | ptrdiff_t off = insert_point - (*adding_to)->list; | ||
| 315 | if (accesslist_new) { | ||
| 316 | memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off); | ||
| 317 | memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash)); | ||
| 318 | memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, (*adding_to)->size - off); | ||
| 319 | *adding_to = accesslist_new; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | } | ||
| 323 | accesslist_clean(*adding_to); | ||
| 324 | |||
| 325 | pthread_mutex_unlock(&g_accesslist_mutex); | ||
| 326 | } | ||
| 327 | |||
| 328 | fclose(fifo); | ||
| 329 | } | ||
| 330 | return NULL; | ||
| 331 | } | ||
| 332 | |||
| 333 | static void * accesslist_adder_worker( void * args ) { | ||
| 334 | (void)args; | ||
| 335 | return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete); | ||
| 336 | } | ||
| 337 | static void * accesslist_deleter_worker( void * args ) { | ||
| 338 | (void)args; | ||
| 339 | return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add); | ||
| 340 | } | ||
| 341 | #endif | ||
| 342 | |||
| 151 | static pthread_t thread_id; | 343 | static pthread_t thread_id; |
| 152 | void accesslist_init( ) { | 344 | void accesslist_init( ) { |
| 153 | pthread_mutex_init(&g_accesslist_mutex, NULL); | 345 | pthread_mutex_init(&g_accesslist_mutex, NULL); |
| 154 | pthread_create( &thread_id, NULL, accesslist_worker, NULL ); | 346 | pthread_create( &thread_id, NULL, accesslist_worker, NULL ); |
| 347 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 348 | if (g_accesslist_pipe_add) | ||
| 349 | pthread_create( &thread_adder_id, NULL, accesslist_adder_worker, NULL ); | ||
| 350 | if (g_accesslist_pipe_delete) | ||
| 351 | pthread_create( &thread_deleter_id, NULL, accesslist_deleter_worker, NULL ); | ||
| 352 | #endif | ||
| 155 | } | 353 | } |
| 156 | 354 | ||
| 157 | void accesslist_deinit( void ) { | 355 | void accesslist_deinit( void ) { |
| 158 | pthread_cancel( thread_id ); | 356 | /* Wake up sleeping worker */ |
| 159 | pthread_mutex_destroy(&g_accesslist_mutex); | 357 | pthread_kill(thread_id, SIGHUP); |
| 160 | 358 | ||
| 161 | if (g_accesslist_old) { | 359 | pthread_mutex_lock(&g_accesslist_mutex); |
| 162 | free(g_accesslist_old->list); | ||
| 163 | free(g_accesslist_old); | ||
| 164 | g_accesslist_old = 0; | ||
| 165 | } | ||
| 166 | 360 | ||
| 167 | if (g_accesslist) { | 361 | g_accesslist = accesslist_free(g_accesslist); |
| 168 | free(g_accesslist->list); | 362 | |
| 169 | free(g_accesslist); | 363 | #ifdef WANT_DYNAMIC_ACCESSLIST |
| 170 | g_accesslist = 0; | 364 | g_accesslist_add = accesslist_free(g_accesslist_add); |
| 171 | } | 365 | g_accesslist_delete = accesslist_free(g_accesslist_delete); |
| 366 | #endif | ||
| 367 | |||
| 368 | pthread_mutex_unlock(&g_accesslist_mutex); | ||
| 369 | pthread_cancel( thread_id ); | ||
| 370 | pthread_mutex_destroy(&g_accesslist_mutex); | ||
| 172 | } | 371 | } |
| 173 | #endif | 372 | #endif |
| 174 | 373 | ||
diff --git a/ot_accesslist.h b/ot_accesslist.h index b38b91a..e86969b 100644 --- a/ot_accesslist.h +++ b/ot_accesslist.h | |||
| @@ -12,11 +12,15 @@ | |||
| 12 | 12 | ||
| 13 | #if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE ) | 13 | #if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE ) |
| 14 | #define WANT_ACCESSLIST | 14 | #define WANT_ACCESSLIST |
| 15 | void accesslist_init( ); | 15 | void accesslist_init( void ); |
| 16 | void accesslist_deinit( ); | 16 | void accesslist_deinit( void ); |
| 17 | int accesslist_hashisvalid( ot_hash hash ); | 17 | int accesslist_hashisvalid( ot_hash hash ); |
| 18 | 18 | ||
| 19 | extern char *g_accesslist_filename; | 19 | extern char *g_accesslist_filename; |
| 20 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 21 | extern char *g_accesslist_pipe_add; | ||
| 22 | extern char *g_accesslist_pipe_delete; | ||
| 23 | #endif | ||
| 20 | 24 | ||
| 21 | #else | 25 | #else |
| 22 | #define accesslist_init( accesslist_filename ) | 26 | #define accesslist_init( accesslist_filename ) |
| @@ -8,8 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | #include <sys/uio.h> | 9 | #include <sys/uio.h> |
| 10 | 10 | ||
| 11 | void mutex_init( ); | 11 | void mutex_init( void ); |
| 12 | void mutex_deinit( ); | 12 | void mutex_deinit( void ); |
| 13 | 13 | ||
| 14 | ot_vector *mutex_bucket_lock( int bucket ); | 14 | ot_vector *mutex_bucket_lock( int bucket ); |
| 15 | ot_vector *mutex_bucket_lock_by_hash( ot_hash hash ); | 15 | ot_vector *mutex_bucket_lock_by_hash( ot_hash hash ); |
| @@ -17,7 +17,7 @@ ot_vector *mutex_bucket_lock_by_hash( ot_hash hash ); | |||
| 17 | void mutex_bucket_unlock( int bucket, int delta_torrentcount ); | 17 | void mutex_bucket_unlock( int bucket, int delta_torrentcount ); |
| 18 | void mutex_bucket_unlock_by_hash( ot_hash hash, int delta_torrentcount ); | 18 | void mutex_bucket_unlock_by_hash( ot_hash hash, int delta_torrentcount ); |
| 19 | 19 | ||
| 20 | size_t mutex_get_torrent_count(); | 20 | size_t mutex_get_torrent_count(void); |
| 21 | 21 | ||
| 22 | typedef enum { | 22 | typedef enum { |
| 23 | TASK_STATS_CONNS = 0x0001, | 23 | TASK_STATS_CONNS = 0x0001, |
| @@ -40,11 +40,11 @@ enum { | |||
| 40 | 40 | ||
| 41 | void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event_data ); | 41 | void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event_data ); |
| 42 | void stats_deliver( int64 sock, int tasktype ); | 42 | void stats_deliver( int64 sock, int tasktype ); |
| 43 | void stats_cleanup(); | 43 | void stats_cleanup( void ); |
| 44 | size_t return_stats_for_tracker( char *reply, int mode, int format ); | 44 | size_t return_stats_for_tracker( char *reply, int mode, int format ); |
| 45 | size_t stats_return_tracker_version( char *reply ); | 45 | size_t stats_return_tracker_version( char *reply ); |
| 46 | void stats_init( ); | 46 | void stats_init( void ); |
| 47 | void stats_deinit( ); | 47 | void stats_deinit( void ); |
| 48 | 48 | ||
| 49 | extern const char *g_version_rijndael_c; | 49 | extern const char *g_version_rijndael_c; |
| 50 | extern const char *g_version_livesync_c; | 50 | extern const char *g_version_livesync_c; |
diff --git a/trackerlogic.h b/trackerlogic.h index 87b9138..ef59179 100644 --- a/trackerlogic.h +++ b/trackerlogic.h | |||
| @@ -133,7 +133,6 @@ struct ot_workstruct { | |||
| 133 | char *peer_id; | 133 | char *peer_id; |
| 134 | 134 | ||
| 135 | /* HTTP specific, non static */ | 135 | /* HTTP specific, non static */ |
| 136 | int keep_alive; | ||
| 137 | char *request; | 136 | char *request; |
| 138 | ssize_t request_size; | 137 | ssize_t request_size; |
| 139 | ssize_t header_size; | 138 | ssize_t header_size; |
| @@ -143,6 +142,8 @@ struct ot_workstruct { | |||
| 143 | /* Entropy state for rand48 function so that threads don't need to acquire mutexes for | 142 | /* Entropy state for rand48 function so that threads don't need to acquire mutexes for |
| 144 | global random() or arc4random() state, which causes heavy load on linuxes */ | 143 | global random() or arc4random() state, which causes heavy load on linuxes */ |
| 145 | uint16_t rand48_state[3]; | 144 | uint16_t rand48_state[3]; |
| 145 | |||
| 146 | int keep_alive; | ||
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 148 | /* | 149 | /* |
| @@ -163,7 +164,7 @@ struct ot_workstruct { | |||
| 163 | #error Live logging networks disabled at the moment. | 164 | #error Live logging networks disabled at the moment. |
| 164 | #endif | 165 | #endif |
| 165 | 166 | ||
| 166 | void trackerlogic_init( ); | 167 | void trackerlogic_init( void ); |
| 167 | void trackerlogic_deinit( void ); | 168 | void trackerlogic_deinit( void ); |
| 168 | void exerr( char * message ); | 169 | void exerr( char * message ); |
| 169 | 170 | ||
