From 0af295617d119045393a903118acc79b7fc9a29e Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 12 Mar 2015 13:07:02 +0800 Subject: [PATCH 1/3] allow empty list --- src/server.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/server.c b/src/server.c index 4fa7bac5..48b5117f 100644 --- a/src/server.c +++ b/src/server.c @@ -1163,9 +1163,6 @@ int main(int argc, char **argv) } else if (strcmp(long_options[option_index].name, "bitcoin-list") == 0) { bitcoin_list = bitcoin_init_list(optarg); size_t cnt = bitcoin_tryload_list(bitcoin_list); - if (cnt == 0) { - FATAL("invalid bitcoin list"); - } LOGI("bitcoin address number: %zu", cnt); } break; From 617874145b55956c686131041ddeda29ce556d86 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 12 Mar 2015 16:09:45 +0800 Subject: [PATCH 2/3] using multi thread to update bitcoin list file --- src/Makefile.am | 4 +- src/Makefile.in | 6 +- src/bitcoin.c | 173 ++++++++++++++++++++++++++++-------------------- src/bitcoin.h | 4 +- src/server.c | 10 ++- 5 files changed, 119 insertions(+), 78 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index bfe93ce8..fb0913e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,9 +54,9 @@ ss_server_SOURCES = utils.c \ ss_local_LDADD = $(SS_COMMON_LIBS) ss_tunnel_LDADD = $(SS_COMMON_LIBS) ss_server_LDADD = $(SS_COMMON_LIBS) -ss_local_LDADD += $(top_builddir)/libudns/libudns.la +ss_local_LDADD += $(top_builddir)/libudns/libudns.la -lpthread ss_tunnel_LDADD += $(top_builddir)/libudns/libudns.la -ss_server_LDADD += $(top_builddir)/libudns/libudns.la +ss_server_LDADD += $(top_builddir)/libudns/libudns.la -lpthread ss_local_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL ss_tunnel_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL diff --git a/src/Makefile.in b/src/Makefile.in index 20e7a113..fbaca156 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -374,9 +374,11 @@ ss_server_SOURCES = utils.c \ bitcoin.c \ server.c -ss_local_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la +ss_local_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la \ + -lpthread ss_tunnel_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la -ss_server_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la +ss_server_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la \ + -lpthread ss_local_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL ss_tunnel_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL ss_server_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_REMOTE diff --git a/src/bitcoin.c b/src/bitcoin.c index 62dac59f..6ec61d57 100644 --- a/src/bitcoin.c +++ b/src/bitcoin.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -589,9 +590,9 @@ struct btc_list { struct btc_client *clients; size_t number; char *file; - time_t last_check_time; - time_t last_modify_time; - pthread_mutex_t lock; + pthread_rwlock_t lock; + pthread_t thread; + int running; }; static int cmp_btc_client(const void *l, const void *r) { @@ -603,98 +604,130 @@ static int cmp_btc_client(const void *l, const void *r) { extern struct btc_list *bitcoin_init_list(const char *file) { struct btc_list *l = calloc(1, sizeof(struct btc_list)); l->clients = NULL; - pthread_mutex_init(&l->lock, NULL); - l->number = 0; - l->file = strdup(file); - l->last_check_time = 0; - l->last_modify_time = 0; + pthread_rwlock_init(&l->lock, NULL); + l->number = 0; + l->file = strdup(file); + l->running = 1; return l; } -extern size_t bitcoin_tryload_list(struct btc_list *list) { +static void *check_list(void *ptr) { + struct btc_list *list = (struct btc_list *)ptr; + time_t last_check_time = 0; + time_t last_modify_time = 0; + struct stat attrib; - FILE *f = NULL; size_t size = 8; - size_t idx = 0; - struct btc_client *clients = NULL; char line[64]; + int running = 1; - int is_need_update = 0; - pthread_mutex_lock(&list->lock); - // update when: 1. last check time over than 10 seconds - // 2. file has been modified - if (time(NULL) > list->last_check_time + 10) { - list->last_check_time = time(NULL); - stat(list->file, &attrib); - if (list->last_modify_time != attrib.st_mtime) { - is_need_update = 1; + while (1) { + pthread_rwlock_rdlock(&list->lock); + running = list->running; + pthread_rwlock_unlock(&list->lock); + + if (running == 0) { + break; // stop thread } - } - pthread_mutex_unlock(&list->lock); - if (is_need_update == 0) { - return 0; - } - f = fopen(list->file, "rb"); - if (f == NULL) { - return 0; - } - - clients = calloc(size, sizeof(struct btc_client)); - while (fgets(line, sizeof(line), f)) { - while (strlen(line) > 0 && !isalpha(line[strlen(line) - 1])) { - line[strlen(line) - 1] = '\0'; + // update when: 1. last check time over than 10 seconds + // 2. file has been modified + if (time(NULL) < last_check_time + 10) { + sleep(1); + continue; } - if (strlen(line) > 35 || strlen(line) < 26) { - continue; // bitcoin address length range: [26, 35] + last_check_time = time(NULL); + + if (stat(list->file, &attrib) != 0) { + continue; } - if (idx >= size) { - size *= 2; - clients = realloc(clients, size * sizeof(struct btc_client)); + if (last_modify_time == attrib.st_mtime) { + continue; } - struct btc_client *c = clients + idx; - strcpy(c->address, line); - idx++; - } - fclose(f); - if (idx == 0) { - free(clients); - return 0; - } - assert(idx <= size); - if (idx != size) { - clients = realloc(clients, idx * sizeof(struct btc_client)); - } - stat(list->file, &attrib); + FILE *f = fopen(list->file, "rb"); + if (f == NULL) { + continue; + } + if (flock(fileno(f), LOCK_EX | LOCK_NB) != 0) { + fclose(f); + continue; + } - qsort(clients, idx, sizeof(struct btc_client), cmp_btc_client); + size_t idx = 0; + struct btc_client *clients = calloc(size, sizeof(struct btc_client)); + while (fgets(line, sizeof(line), f)) { + while (strlen(line) > 0 && !isalpha(line[strlen(line) - 1])) { + line[strlen(line) - 1] = '\0'; + } + if (strlen(line) > 35 || strlen(line) < 26) { + continue; // bitcoin address length range: [26, 35] + } + if (idx >= size) { + size *= 2; + clients = realloc(clients, size * sizeof(struct btc_client)); + } + struct btc_client *c = clients + idx; + strcpy(c->address, line); + idx++; + } + fclose(f); + flock(fileno(f), LOCK_UN); - pthread_mutex_lock(&list->lock); - if (list->clients != NULL) { - free(list->clients); + assert(idx <= size); + if (idx == 0) { + free(clients); + clients = NULL; + } else { + if (idx != size) { + clients = realloc(clients, idx * sizeof(struct btc_client)); + } + qsort(clients, idx, sizeof(struct btc_client), cmp_btc_client); + } + + // update list + pthread_rwlock_wrlock(&list->lock); + if (list->clients != NULL) { + free(list->clients); + } + list->clients = clients; + list->number = idx; + pthread_rwlock_unlock(&list->lock); + + last_modify_time = attrib.st_mtime; } - list->clients = clients; - list->number = idx; - list->last_check_time = time(NULL); - list->last_modify_time = attrib.st_mtime; - pthread_mutex_unlock(&list->lock); - return idx; + return NULL; +} + +extern int bitcoin_setup_update_thread(struct btc_list *list) { + if (pthread_create(&list->thread, NULL, check_list, list) == 0) { + return 1; + } + return 0; // error +} + +extern void bitcoin_clean_update_thread(struct btc_list *list) { + pthread_rwlock_wrlock(&list->lock); + list->running = 0; + pthread_rwlock_unlock(&list->lock); + + pthread_join(list->thread, NULL); } extern int bitcoin_check_address(struct btc_list *list, const char *address) { - struct btc_client key, *res; + struct btc_client key, *res = NULL; memset(&key, 0, sizeof(struct btc_client)); strncpy(key.address, address, 35); - bitcoin_tryload_list(list); + pthread_rwlock_rdlock(&list->lock); + if (list->number > 0) { + res = bsearch(&key, list->clients, list->number, + sizeof(struct btc_client), cmp_btc_client); + } + pthread_rwlock_unlock(&list->lock); - pthread_mutex_lock(&list->lock); - res = bsearch(&key, list->clients, list->number, - sizeof(struct btc_client), cmp_btc_client); - pthread_mutex_unlock(&list->lock); if (res != NULL) { return 1; } diff --git a/src/bitcoin.h b/src/bitcoin.h index 746d99f2..36b786f4 100644 --- a/src/bitcoin.h +++ b/src/bitcoin.h @@ -34,7 +34,7 @@ extern int bitcoin_verify_message(const char *address, const unsigned char *sig_ struct btc_client; struct btc_list; extern struct btc_list *bitcoin_init_list(); -extern size_t bitcoin_tryload_list(struct btc_list *list); extern int bitcoin_check_address(struct btc_list *list, const char *address); - +extern int bitcoin_setup_update_thread(struct btc_list *list); +extern void bitcoin_clean_update_thread(struct btc_list *list); #endif diff --git a/src/server.c b/src/server.c index 48b5117f..81e37225 100644 --- a/src/server.c +++ b/src/server.c @@ -1161,9 +1161,11 @@ int main(int argc, char **argv) LOGI("initialize acl..."); acl = !init_acl(optarg); } else if (strcmp(long_options[option_index].name, "bitcoin-list") == 0) { + LOGI("bitcoin list file: %s", optarg); bitcoin_list = bitcoin_init_list(optarg); - size_t cnt = bitcoin_tryload_list(bitcoin_list); - LOGI("bitcoin address number: %zu", cnt); + if (bitcoin_setup_update_thread(bitcoin_list) == 0) { + FATAL("setup bitcoin check list thread failure"); + } } break; case 's': @@ -1406,6 +1408,10 @@ int main(int argc, char **argv) if (udprelay) { free_udprelay(); } + + if (bitcoin_list) { + bitcoin_clean_update_thread(bitcoin_list); + } resolv_shutdown(loop); From 62468c81bf946c3e6fca077e62ed2c96214346d6 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 12 Mar 2015 16:34:16 +0800 Subject: [PATCH 3/3] use flock when write bitcoin list file --- scripts/generate.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/generate.php b/scripts/generate.php index c51fc69f..5312c285 100644 --- a/scripts/generate.php +++ b/scripts/generate.php @@ -67,11 +67,29 @@ function dump_for_ss_server($exist_txs) { $address[] = $_tx['address']; } $str = implode("\n", $address)."\n"; + LOGI("try dump ".count($address)." address to ss_server_file"); - LOGI("dump ".count($address)." address to ss_server_file"); - if (file_put_contents($_CFG['ss_server_file'], $str) == false) { - LOGI("write file fail: {$_CFG['ss_server_file']}"); + $exist = file_exists($_CFG['ss_server_file']); + $fp = fopen($_CFG['ss_server_file'], $exist ? "r+" : "w"); + if (!$fp) { + LOGI("write file failure: {$_CFG['ss_server_file']}"); + return; + } + + // use flock when write file + for ($i = 0; $i < 3; $i++) { // try 3 times if need + if (!flock($fp, LOCK_EX | LOCK_NB)) { + sleep(3);continue; + } + ftruncate($fp, 0); + fwrite($fp, $str); + fflush($fp); + flock($fp, LOCK_UN); + + LOGI("write file success: {$_CFG['ss_server_file']}"); + break; } + fclose($fp); }