Browse Source

using multi thread to update bitcoin list file

pull/286/head^2^2
kevin 9 years ago
parent
commit
617874145b
5 changed files with 117 additions and 76 deletions
  1. 4
      src/Makefile.am
  2. 6
      src/Makefile.in
  3. 169
      src/bitcoin.c
  4. 4
      src/bitcoin.h
  5. 10
      src/server.c

4
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

6
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

169
src/bitcoin.c

@ -26,6 +26,7 @@
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
@ -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;
while (1) {
pthread_rwlock_rdlock(&list->lock);
running = list->running;
pthread_rwlock_unlock(&list->lock);
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;
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;
}
// 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;
}
last_check_time = time(NULL);
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 (stat(list->file, &attrib) != 0) {
continue;
}
if (strlen(line) > 35 || strlen(line) < 26) {
continue; // bitcoin address length range: [26, 35]
if (last_modify_time == attrib.st_mtime) {
continue;
}
if (idx >= size) {
size *= 2;
clients = realloc(clients, size * sizeof(struct btc_client));
FILE *f = fopen(list->file, "rb");
if (f == NULL) {
continue;
}
if (flock(fileno(f), LOCK_EX | LOCK_NB) != 0) {
fclose(f);
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));
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);
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;
}
stat(list->file, &attrib);
qsort(clients, idx, sizeof(struct btc_client), cmp_btc_client);
return NULL;
}
pthread_mutex_lock(&list->lock);
if (list->clients != NULL) {
free(list->clients);
extern int bitcoin_setup_update_thread(struct btc_list *list) {
if (pthread_create(&list->thread, NULL, check_list, list) == 0) {
return 1;
}
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 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);
return idx;
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;
}

4
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

10
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);

Loading…
Cancel
Save