From 86087825a9c7dcd068b556ca0f06c31f2a8ff5ac Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 2 Nov 2014 10:24:32 +0800 Subject: [PATCH] refine library interface --- src/Makefile.am | 1 + src/acl.c | 5 +- src/local.c | 133 +++++++++++++++++++++++++++++++++++++++++++++- src/shadowsocks.h | 24 ++++++--- src/utils.h | 32 ++++++++++- 5 files changed, 183 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index b0be4c68..2fd3b3c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,5 +71,6 @@ lib_LTLIBRARIES = libshadowsocks.la libshadowsocks_la_SOURCES = $(ss_local_SOURCES) libshadowsocks_la_CFLAGS = $(ss_local_CFLAGS) -DLIB_ONLY libshadowsocks_la_LIBADD = $(ss_local_LDADD) +include_HEADERS = src/shadowsocks.h endif diff --git a/src/acl.c b/src/acl.c index 553ba163..88265bc5 100644 --- a/src/acl.c +++ b/src/acl.c @@ -69,7 +69,10 @@ int init_acl(const char *path) cork_string_array_init(&acl_domain_array); FILE *f = fopen(path, "r"); - if (f == NULL) FATAL("Invalid acl path."); + if (f == NULL) { + LOGE("Invalid acl path."); + return -1; + } char line[256]; while(!feof(f)) diff --git a/src/local.c b/src/local.c index bc20f42a..d7f80a36 100644 --- a/src/local.c +++ b/src/local.c @@ -43,6 +43,11 @@ #include "config.h" #endif +#ifdef LIB_ONLY +#include +#include "shadowsocks.h" +#endif + #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include @@ -986,8 +991,7 @@ int main (int argc, char **argv) else if (option_index == 1) { LOGD("initialize acl..."); - acl = 1; - init_acl(optarg); + acl = !init_acl(optarg); } break; case 's': @@ -1160,5 +1164,130 @@ int main (int argc, char **argv) return 0; } +#else + +static int running = 0; +static pthread_t worker_tid; + +static void * +start_worker(void *arg) +{ + srand(time(NULL)); + + profile_t profile = *((profile_t *)arg); + char *remote_host = profile.remote_host; + char *local_addr = profile.local_addr; + char *method = profile.method; + char *password = profile.password; + char *log = profile.log; + int remote_port = profile.remote_port; + int local_port = profile.local_port; + int timeout = profile.timeout; + + udprelay = profile.udp_relay; + fast_open = profile.fast_open; + verbose = profile.verbose; + + char local_port_str[16]; + char remote_port_str[16]; + sprintf(local_port_str, "%d", local_port); + sprintf(remote_port_str, "%d", remote_port); + + if (profile.acl != NULL) + { + acl = !init_acl(profile.acl); + } + + if (local_addr == NULL) local_addr = "0.0.0.0"; + + USE_LOGFILE(log); + +#ifdef __MINGW32__ + winsock_init(); +#else + // ignore SIGPIPE + signal(SIGPIPE, SIG_IGN); + signal(SIGABRT, SIG_IGN); +#endif + + // Setup keys + LOGD("initialize ciphers... %s", method); + int m = enc_init(password, method); + + // Setup socket + int listenfd; + listenfd = create_and_bind(local_addr, local_port_str); + if (listenfd < 0) + { + FATAL("bind() error.."); + } + if (listen(listenfd, SOMAXCONN) == -1) + { + FATAL("listen() error."); + } + setnonblocking(listenfd); + LOGD("server listening at port %s.", local_port_str); + + // Setup proxy context + struct listen_ctx listen_ctx; + + listen_ctx.remote_num = 1; + listen_ctx.remote_addr = malloc(sizeof(ss_addr_t)); + listen_ctx.remote_addr[0].host = remote_host; + listen_ctx.remote_addr[0].port = remote_port_str; + listen_ctx.timeout = timeout; + listen_ctx.fd = listenfd; + listen_ctx.method = m; + listen_ctx.iface = NULL; + + struct ev_loop *loop = ev_default_loop(0); + if (!loop) + { + FATAL("ev_loop error."); + } + ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); + ev_io_start (loop, &listen_ctx.io); + + // Setup UDP + if (udprelay) + { + LOGD("udprelay enabled."); + udprelay_init(local_addr, local_port_str, remote_host, remote_port_str, m, listen_ctx.timeout, NULL); + } + + ev_run (loop, 0); + +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + + return 0; +} + +void stop_ss_service(int blocking) +{ + if (running) { + struct ev_loop *loop = ev_default_loop(0); + ev_break(loop, EVBREAK_ALL); + if (blocking) + { + pthread_join(worker_tid, NULL); + } + } +} + +int start_ss_service(profile_t profile) +{ + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + int err = pthread_create(&worker_tid, NULL, start_worker, &profile); + + if (err) return -1; + return 0; + +} #endif diff --git a/src/shadowsocks.h b/src/shadowsocks.h index 5f7da99c..7a802c4d 100644 --- a/src/shadowsocks.h +++ b/src/shadowsocks.h @@ -23,21 +23,29 @@ #define _SHADOWSOCKS_H typedef struct { - char *server; // server hostname or ip + char *remote_host; // hostname or ip of remote server + char *local_addr; // local ip to bind char *method; // encryption method - char *passwd; // password of server - char *config; // file path to config + char *password; // password of remote server char *acl; // file path to acl - int server_port; // port number of server - int local_port; // port number of local + char *log; // file path to log + int remote_port; // port number of remote server + int local_port; // port number of local server int timeout; // connection timeout - int fast_open; // tcp fast open + int fast_open; // enable tcp fast open + int udp_relay; // enable udp relay int verbose; // verbose mode } profile_t; // create and start a shadowsocks service, -// if success, return the pid. +// if success, return the tid. // if not, return -1 -int create_ss_service (profile_t profile, char *log_file); +int start_ss_service(profile_t profile); + +// stop the current shadowsocks service, +// if blocking set true, this call will be blocked until no events left. +// call this function in blocking mode would take quite long time, depends on +// the timeout you set. +void stop_ss_service(int blocking); #endif // _SHADOWSOCKS_H diff --git a/src/utils.h b/src/utils.h index 607b7956..5be61dbd 100644 --- a/src/utils.h +++ b/src/utils.h @@ -42,7 +42,37 @@ #define STR(x) #x #define TOSTR(x) STR(x) -#ifdef _WIN32 +#ifdef LIB_ONLY + +#define TIME_FORMAT "%Y-%m-%d %H:%M:%S" + +#define USE_SYSLOG(ident) + +FILE *logfile; + +#define USE_LOGFILE(ident) do {\ + if (ident != NULL) logfile = fopen(ident, "w+");}\ +while(0) + +#define LOGD(format, ...) do {\ + if (logfile != NULL) {\ + time_t now = time(NULL);\ + char timestr[20];\ + strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ + fprintf(logfile, " %s INFO: " format "\n", timestr, ##__VA_ARGS__);}\ + }\ +while(0) + +#define LOGE(format, ...) do {\ + if (logfile != NULL) {\ + time_t now = time(NULL);\ + char timestr[20];\ + strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ + fprintf(logfile, " %s ERROR: " format "\n", timestr, ##__VA_ARGS__);}\ + }\ +while(0) + +#elif defined(_WIN32) #define TIME_FORMAT "%Y-%m-%d %H:%M:%S"