diff --git a/configure.ac b/configure.ac index d7cef6b6..a7a17943 100755 --- a/configure.ac +++ b/configure.ac @@ -66,7 +66,7 @@ dnl Add library for mingw case $host in *-mingw*) CFLAGS="$CFLAGS -mno-ms-bitfields" - LIBS="$LIBS -ladvapi32 -lgdi32 -lws2_32 -lcrypt32" + LIBS="$LIBS -lws2_32" ;; *-cygwin*) CFLAGS="$CFLAGS -mno-ms-bitfields" @@ -93,6 +93,10 @@ case $host in os_support=linux AC_MSG_RESULT(Linux) ;; + *-mingw*) + os_support=mingw + AC_MSG_RESULT(MinGW) + ;; *) AC_MSG_RESULT(transparent proxy does not support for $host) ;; @@ -161,6 +165,10 @@ AC_CHECK_HEADERS([net/if.h], [], [], ]) case $host in + *-mingw*) + AC_DEFINE([CONNECT_IN_PROGRESS], [WSAEWOULDBLOCK], [errno for incomplete non-blocking connect(2)]) + AC_CHECK_HEADERS([winsock2.h ws2tcpip.h], [], [AC_MSG_ERROR([Missing MinGW headers])], []) + ;; *-linux*) AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)]) dnl Checks for netfilter headers @@ -219,6 +227,12 @@ AC_CHECK_LIB(socket, connect) dnl Checks for library functions. AC_CHECK_FUNCS([malloc memset posix_memalign socket]) +AC_ARG_WITH(ev, + AS_HELP_STRING([--with-ev=DIR], [use a specific libev library]), + [CFLAGS="$CFLAGS -I$withval/include" + CPPFLAGS="$CPPFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib"] +) AC_CHECK_HEADERS([ev.h libev/ev.h], [], []) AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])]) diff --git a/src/Makefile.am b/src/Makefile.am index dcc5fd9b..4efb8905 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,7 +19,10 @@ SS_COMMON_LIBS += -lbloom -lcork -lcorkipset endif SS_COMMON_LIBS += -lev -lsodium -lm -bin_PROGRAMS = ss-local ss-tunnel ss-server ss-manager +bin_PROGRAMS = ss-local ss-tunnel ss-server +if !BUILD_WINCOMPAT +bin_PROGRAMS += ss-manager +endif sni_src = http.c \ tls.c @@ -30,41 +33,37 @@ acl_src = rule.c \ crypto_src = crypto.c \ aead.c \ stream.c \ - ppbloom.c \ + ppbloom.c \ base64.c plugin_src = plugin.c -ss_local_SOURCES = utils.c \ - jconf.c \ - json.c \ - udprelay.c \ - cache.c \ - netutils.c \ - local.c \ +common_src = utils.c \ + jconf.c \ + json.c \ + udprelay.c \ + cache.c \ + netutils.c + +if BUILD_WINCOMPAT +common_src += winsock.c +endif + +ss_local_SOURCES = local.c \ + $(common_src) \ $(crypto_src) \ $(plugin_src) \ $(sni_src) \ $(acl_src) -ss_tunnel_SOURCES = utils.c \ - jconf.c \ - json.c \ - udprelay.c \ - cache.c \ - netutils.c \ - tunnel.c \ +ss_tunnel_SOURCES = tunnel.c \ + $(common_src) \ $(crypto_src) \ $(plugin_src) -ss_server_SOURCES = utils.c \ - netutils.c \ - jconf.c \ - json.c \ - udprelay.c \ - cache.c \ - resolv.c \ +ss_server_SOURCES = resolv.c \ server.c \ + $(common_src) \ $(crypto_src) \ $(plugin_src) \ $(sni_src) \ diff --git a/src/aead.c b/src/aead.c index b85d0384..56cf30ad 100644 --- a/src/aead.c +++ b/src/aead.c @@ -31,11 +31,14 @@ #include #include +#ifndef __MINGW32__ #include +#endif #include "ppbloom.h" #include "aead.h" #include "utils.h" +#include "winsock.h" #define NONE (-1) #define AES128GCM 0 diff --git a/src/crypto.c b/src/crypto.c index c783a6f2..ba74db79 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -372,7 +372,7 @@ crypto_parse_key(const char *base64, uint8_t *key, size_t key_len) rand_bytes(key, key_len); base64_encode(out_key, out_len, key, key_len); LOGE("Invalid key for your chosen cipher!"); - LOGE("It requires a %zu-byte key encoded with URL-safe Base64", key_len); + LOGE("It requires a " SIZE_FMT "-byte key encoded with URL-safe Base64", key_len); LOGE("Generating a new random key: %s", out_key); FATAL("Please use the key above or input a valid key"); return key_len; diff --git a/src/crypto.h b/src/crypto.h index 69a46945..c86d40f0 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -23,7 +23,9 @@ #ifndef _CRYPTO_H #define _CRYPTO_H +#ifndef __MINGW32__ #include +#endif #include #include #include diff --git a/src/json.c b/src/json.c index 6012bad7..2a919009 100644 --- a/src/json.c +++ b/src/json.c @@ -35,6 +35,12 @@ #endif #endif +#ifdef __MINGW32__ +#define CONV_PTR (uintptr_t) +#else +#define CONV_PTR (unsigned long) +#endif + const struct _json_value json_value_none; #include @@ -138,7 +144,7 @@ static int new_value (json_state * state, values_size = sizeof (*value->u.object.values) * value->u.object.length; if (! (value->u.object.values = (json_object_entry *) json_alloc - (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + (state, values_size + (CONV_PTR value->u.object.values), 0)) ) { return 0; } diff --git a/src/local.c b/src/local.c index b74caac9..47ff491c 100644 --- a/src/local.c +++ b/src/local.c @@ -33,12 +33,12 @@ #include #include #include - +#ifndef __MINGW32__ #include #include #include #include - +#endif #ifdef LIB_ONLY #include "shadowsocks.h" #endif @@ -59,6 +59,7 @@ #include "tls.h" #include "plugin.h" #include "local.h" +#include "winsock.h" #ifndef LIB_ONLY #ifdef __APPLE__ @@ -104,8 +105,10 @@ static int udp_fd = 0; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; +#ifndef __MINGW32__ static struct ev_signal sigchld_watcher; static struct ev_signal sigusr1_watcher; +#endif #ifdef HAVE_SETRLIMIT #ifndef LIB_ONLY @@ -135,6 +138,7 @@ static server_t *new_server(int fd); static struct cork_dllist connections; +#ifndef __MINGW32__ int setnonblocking(int fd) { @@ -144,6 +148,7 @@ setnonblocking(int fd) } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif int create_and_bind(const char *addr, const char *port) @@ -1213,18 +1218,22 @@ signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { +#ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) LOGE("plugin service exit unexpectedly"); else return; case SIGUSR1: +#endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_signal_stop(EV_DEFAULT, &sigusr1_watcher); +#endif keep_resolving = 0; ev_unloop(EV_A_ EVUNLOOP_ALL); } @@ -1276,7 +1285,9 @@ main(int argc, char **argv) char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; +#ifndef __MINGW32__ char tmp_port[8]; +#endif srand(time(NULL)); @@ -1501,7 +1512,12 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } +#ifdef __MINGW32__ + winsock_init(); +#endif + if (plugin != NULL) { +#ifndef __MINGW32__ uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); @@ -1511,6 +1527,9 @@ main(int argc, char **argv) plugin_port = tmp_port; LOGI("plugin \"%s\" enabled", plugin); +#else + FATAL("plugins not implemented in MinGW port"); +#endif } if (method == NULL) { @@ -1560,6 +1579,7 @@ main(int argc, char **argv) LOGI("resolving hostname to IPv6 address first"); } +#ifndef __MINGW32__ if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; @@ -1577,10 +1597,13 @@ main(int argc, char **argv) FATAL("failed to start the plugin"); } } +#endif +#ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); +#endif // Setup keys LOGI("initializing ciphers... %s", method); @@ -1621,8 +1644,10 @@ main(int argc, char **argv) ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); +#endif if (strcmp(local_addr, ":") > 0) LOGI("listening at [%s]:%s", local_addr, local_port); @@ -1674,6 +1699,7 @@ main(int argc, char **argv) else #endif +#ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); @@ -1682,6 +1708,7 @@ main(int argc, char **argv) if (geteuid() == 0) { LOGI("running from root user"); } +#endif // Init connections cork_dllist_init(&connections); @@ -1694,9 +1721,11 @@ main(int argc, char **argv) } // Clean up +#ifndef __MINGW32__ if (plugin != NULL) { stop_plugin(); } +#endif if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx.io); @@ -1711,6 +1740,10 @@ main(int argc, char **argv) free_udprelay(); } +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + return 0; } @@ -1743,6 +1776,10 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); +#ifdef __MINGW32__ + winsock_init(); +#endif + USE_LOGFILE(log); if (profile.acl != NULL) { @@ -1753,18 +1790,22 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat local_addr = "127.0.0.1"; } +#ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); +#endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ ev_signal_init(&sigusr1_watcher, signal_cb, SIGUSR1); ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigusr1_watcher); ev_signal_start(EV_DEFAULT, &sigchld_watcher); +#endif // Setup keys LOGI("initializing ciphers... %s", method); @@ -1848,6 +1889,10 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat free_udprelay(); } +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + return 0; } diff --git a/src/netutils.c b/src/netutils.c index d4254b71..1c119d67 100644 --- a/src/netutils.c +++ b/src/netutils.c @@ -28,10 +28,12 @@ #include "config.h" #endif +#ifndef __MINGW32__ #include #include #include #include +#endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include diff --git a/src/netutils.h b/src/netutils.h index e5c98707..1565dcf2 100644 --- a/src/netutils.h +++ b/src/netutils.h @@ -23,7 +23,11 @@ #ifndef _NETUTILS_H #define _NETUTILS_H +#ifdef __MINGW32__ +#include "winsock.h" +#else #include +#endif #ifdef HAVE_LINUX_TCP_H #include diff --git a/src/plugin.c b/src/plugin.c index c3d2f5a5..f20c49ed 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -24,6 +24,8 @@ #include "config.h" #endif +#ifndef __MINGW32__ + #include #include #include @@ -299,3 +301,5 @@ is_plugin_running() } return 0; } + +#endif diff --git a/src/resolv.c b/src/resolv.c index 3c12c7f5..7e7e42b6 100644 --- a/src/resolv.c +++ b/src/resolv.c @@ -32,13 +32,13 @@ #include #include #include - +#ifndef __MINGW32__ #include #include #include #include #include - +#endif #include #ifdef HAVE_LIBEV_EV_H @@ -52,6 +52,13 @@ #include "resolv.h" #include "utils.h" #include "netutils.h" +#include "winsock.h" + +#ifdef __MINGW32__ +#define CONV_STATE_CB (ares_sock_state_cb) +#else +#define CONV_STATE_CB +#endif /* * Implement DNS resolution interface using libc-ares @@ -147,7 +154,7 @@ resolv_init(struct ev_loop *loop, char *nameservers, int ipv6first) memset(&default_ctx, 0, sizeof(struct resolv_ctx)); default_ctx.options.sock_state_cb_data = &default_ctx; - default_ctx.options.sock_state_cb = resolv_sock_state_cb; + default_ctx.options.sock_state_cb = CONV_STATE_CB resolv_sock_state_cb; default_ctx.options.timeout = 3000; default_ctx.options.tries = 2; diff --git a/src/resolv.h b/src/resolv.h index 993692d4..e211abc6 100644 --- a/src/resolv.h +++ b/src/resolv.h @@ -31,7 +31,9 @@ #endif #include +#ifndef __MINGW32__ #include +#endif struct resolv_query; diff --git a/src/server.c b/src/server.c index 3132c4d4..ab3ce1a0 100644 --- a/src/server.c +++ b/src/server.c @@ -35,14 +35,14 @@ #include #include #include - +#ifndef __MINGW32__ #include #include #include #include #include #include - +#endif #include #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) @@ -56,6 +56,7 @@ #include "acl.h" #include "plugin.h" #include "server.h" +#include "winsock.h" #ifndef EAGAIN #define EAGAIN EWOULDBLOCK @@ -134,15 +135,20 @@ static char *manager_addr = NULL; uint64_t tx = 0; uint64_t rx = 0; +#ifndef __MINGW32__ ev_timer stat_update_watcher; +#endif ev_timer block_list_watcher; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; +#ifndef __MINGW32__ static struct ev_signal sigchld_watcher; +#endif static struct cork_dllist connections; +#ifndef __MINGW32__ static void stat_update_cb(EV_P_ ev_timer *watcher, int revents) { @@ -218,6 +224,7 @@ stat_update_cb(EV_P_ ev_timer *watcher, int revents) close(sfd); } +#endif static void free_connections(struct ev_loop *loop) @@ -320,6 +327,7 @@ setfastopen(int fd) return s; } +#ifndef __MINGW32__ int setnonblocking(int fd) { @@ -329,6 +337,7 @@ setnonblocking(int fd) } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif int create_and_bind(const char *host, const char *port, int mptcp) @@ -1409,16 +1418,20 @@ signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { +#ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) LOGE("plugin service exit unexpectedly"); else return; +#endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); +#endif ev_unloop(EV_A_ EVUNLOOP_ALL); } } @@ -1493,7 +1506,9 @@ main(int argc, char **argv) char *server_port = NULL; char *plugin_opts = NULL; char *plugin_port = NULL; +#ifndef __MINGW32__ char tmp_port[8]; +#endif int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; @@ -1717,7 +1732,12 @@ main(int argc, char **argv) remote_port = server_port; +#ifdef __MINGW32__ + winsock_init(); +#endif + if (plugin != NULL) { +#ifndef __MINGW32__ uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); @@ -1725,6 +1745,9 @@ main(int argc, char **argv) snprintf(tmp_port, 8, "%d", port); plugin_port = server_port; server_port = tmp_port; +#else + FATAL("plugins not implemented in MinGW port"); +#endif } if (method == NULL) { @@ -1782,16 +1805,20 @@ main(int argc, char **argv) LOGI("enable TCP no-delay"); } +#ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); +#endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); - ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ + ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); +#endif // setup keys LOGI("initializing ciphers... %s", method); @@ -1808,6 +1835,7 @@ main(int argc, char **argv) if (nameservers != NULL) LOGI("using nameserver: %s", nameservers); +#ifndef __MINGW32__ // Start plugin server if (plugin != NULL) { int len = 0; @@ -1827,6 +1855,7 @@ main(int argc, char **argv) FATAL("failed to start the plugin"); } } +#endif // initialize listen context listen_ctx_t listen_ctx_list[server_num]; @@ -1888,14 +1917,17 @@ main(int argc, char **argv) } } +#ifndef __MINGW32__ if (manager_addr != NULL) { ev_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL); ev_timer_start(EV_DEFAULT, &stat_update_watcher); } +#endif ev_timer_init(&block_list_watcher, block_list_clear_cb, UPDATE_INTERVAL, UPDATE_INTERVAL); ev_timer_start(EV_DEFAULT, &block_list_watcher); +#ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); @@ -1904,6 +1936,7 @@ main(int argc, char **argv) if (geteuid() == 0) { LOGI("running from root user"); } +#endif // init block list init_block_list(); @@ -1921,15 +1954,19 @@ main(int argc, char **argv) // Free block list free_block_list(); +#ifndef __MINGW32__ if (manager_addr != NULL) { ev_timer_stop(EV_DEFAULT, &stat_update_watcher); } +#endif ev_timer_stop(EV_DEFAULT, &block_list_watcher); +#ifndef __MINGW32__ if (plugin != NULL) { stop_plugin(); } +#endif // Clean up @@ -1953,5 +1990,9 @@ main(int argc, char **argv) free_udprelay(); } +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + return 0; } diff --git a/src/stream.h b/src/stream.h index 97742703..2972a67b 100644 --- a/src/stream.h +++ b/src/stream.h @@ -23,7 +23,9 @@ #ifndef _STREAM_H #define _STREAM_H +#ifndef __MINGW32__ #include +#endif #include #include #include diff --git a/src/tls.c b/src/tls.c index 0b2f4a4d..863ae9ef 100644 --- a/src/tls.c +++ b/src/tls.c @@ -36,7 +36,9 @@ #include #include /* malloc() */ #include /* strncpy() */ +#ifndef __MINGW32__ #include +#endif #include "tls.h" #include "protocol.h" diff --git a/src/tunnel.c b/src/tunnel.c index 2f8b3373..fc9be825 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -29,13 +29,13 @@ #include #include #include - +#ifndef __MINGW32__ #include #include #include #include #include - +#endif #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -52,6 +52,7 @@ #include "utils.h" #include "plugin.h" #include "tunnel.h" +#include "winsock.h" #ifndef EAGAIN #define EAGAIN EWOULDBLOCK @@ -98,8 +99,11 @@ static int no_delay = 0; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; +#ifndef __MINGW32__ static struct ev_signal sigchld_watcher; +#endif +#ifndef __MINGW32__ static int setnonblocking(int fd) { @@ -109,6 +113,7 @@ setnonblocking(int fd) } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif int create_and_bind(const char *addr, const char *port) @@ -738,16 +743,20 @@ signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { +#ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) LOGE("plugin service exit unexpectedly"); else return; +#endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); +#endif keep_resolving = 0; ev_unloop(EV_A_ EVUNLOOP_ALL); } @@ -778,7 +787,9 @@ main(int argc, char **argv) char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; +#ifndef __MINGW32__ char tmp_port[8]; +#endif int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; @@ -993,7 +1004,12 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } +#ifdef __MINGW32__ + winsock_init(); +#endif + if (plugin != NULL) { +#ifndef __MINGW32__ uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); @@ -1003,6 +1019,9 @@ main(int argc, char **argv) plugin_port = tmp_port; LOGI("plugin \"%s\" enabled", plugin); +#else + FATAL("plugins not implemented in MinGW port"); +#endif } if (method == NULL) { @@ -1046,6 +1065,7 @@ main(int argc, char **argv) FATAL("tunnel port is not defined"); } +#ifndef __MINGW32__ if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; @@ -1062,17 +1082,22 @@ main(int argc, char **argv) FATAL("failed to start the plugin"); } } +#endif +#ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); +#endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); - ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); +#ifndef __MINGW32__ + ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); +#endif // Setup keys LOGI("initializing ciphers... %s", method); @@ -1149,6 +1174,7 @@ main(int argc, char **argv) LOGI("TCP relay disabled"); } +#ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); @@ -1157,12 +1183,19 @@ main(int argc, char **argv) if (geteuid() == 0) { LOGI("running from root user"); } +#endif ev_run(loop, 0); +#ifndef __MINGW32__ if (plugin != NULL) { stop_plugin(); } +#endif + +#ifdef __MINGW32__ + winsock_cleanup(); +#endif return 0; } diff --git a/src/udprelay.c b/src/udprelay.c index 2b774d27..24d55fd2 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -29,13 +29,13 @@ #include #include #include - +#ifndef __MINGW32__ #include #include #include #include #include - +#endif #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -52,6 +52,7 @@ #include "netutils.h" #include "cache.h" #include "udprelay.h" +#include "winsock.h" #ifdef MODULE_REMOTE #define MAX_UDP_CONN_NUM 512 @@ -105,6 +106,7 @@ static int buf_size = DEFAULT_PACKET_SIZE * 2; static int server_num = 0; static server_ctx_t *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; +#ifndef __MINGW32__ static int setnonblocking(int fd) { @@ -114,6 +116,7 @@ setnonblocking(int fd) } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif #if defined(MODULE_REMOTE) && defined(SO_BROADCAST) static int @@ -724,7 +727,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents) goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { - LOGI("[udp] remote_recv_recvfrom fragmentation, MTU at least be: %zd", r + PACKET_HEADER_SIZE); + LOGI("[udp] remote_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); } } @@ -798,7 +801,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: %zd", buf->len + PACKET_HEADER_SIZE); + LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -902,7 +905,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) goto CLEAN_UP; } else if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: %zd", buf->len + PACKET_HEADER_SIZE); + LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -924,7 +927,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { - LOGI("[udp] server_recv_recvfrom fragmentation, MTU at least be: %zd", r + PACKET_HEADER_SIZE); + LOGI("[udp] server_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); } } @@ -1208,7 +1211,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len > packet_size) { if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: %zd", buf->len + PACKET_HEADER_SIZE); + LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } @@ -1225,7 +1228,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len - addr_header_len > packet_size) { if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: %zd", buf->len - addr_header_len + PACKET_HEADER_SIZE); + LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len - addr_header_len + PACKET_HEADER_SIZE); } } diff --git a/src/utils.c b/src/utils.c index b9142e7e..9461afd3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -25,12 +25,14 @@ #endif #include -#include #include -#include #include +#ifndef __MINGW32__ +#include +#include #include #include +#endif #include #include @@ -55,12 +57,14 @@ FILE *logfile; int use_syslog = 0; #endif +#ifndef __MINGW32__ void ERROR(const char *s) { char *msg = strerror(errno); LOGE("%s: %s", s, msg); } +#endif int use_tty = 1; @@ -102,6 +106,7 @@ ss_isnumeric(const char *s) int run_as(const char *user) { +#ifndef __MINGW32__ if (user[0]) { /* Convert user to a long integer if it is a non-negative number. * -1 means it is a user name. */ @@ -195,6 +200,9 @@ run_as(const char *user) } #endif } +#else + LOGE("run_as(): not implemented in MinGW port"); +#endif return 1; } @@ -400,6 +408,7 @@ usage() void daemonize(const char *path) { +#ifndef __MINGW32__ /* Our process ID and Session ID */ pid_t pid, sid; @@ -444,6 +453,9 @@ daemonize(const char *path) close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); +#else + LOGE("daemonize(): not implemented in MinGW port"); +#endif } #ifdef HAVE_SETRLIMIT @@ -478,6 +490,7 @@ set_nofile(int nofile) char * get_default_conf(void) { +#ifndef __MINGW32__ static char sysconf[] = "/etc/shadowsocks-libev/config.json"; static char userconf[PATH_MAX] = { 0 }; char *conf_home; @@ -498,4 +511,7 @@ get_default_conf(void) // If not, fall back to the system-wide config. return sysconf; +#else + return "config.json"; +#endif } diff --git a/src/utils.h b/src/utils.h index 09353b67..3b8167f9 100644 --- a/src/utils.h +++ b/src/utils.h @@ -87,6 +87,35 @@ extern FILE *logfile; #else // not LIB_ONLY +#ifdef __MINGW32__ + +#define USE_TTY() +#define USE_SYSLOG(ident, _cond) +#define USE_LOGFILE(ident) +#define TIME_FORMAT "%Y-%m-%d %H:%M:%S" +#define LOGI(format, ...) \ + do { \ + time_t now = time(NULL); \ + char timestr[20]; \ + strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ + fprintf(stdout, " %s INFO: " format "\n", timestr, \ + ## __VA_ARGS__); \ + } \ + while (0) + +#define LOGE(format, ...) \ + do { \ + time_t now = time(NULL); \ + char timestr[20]; \ + strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ + fprintf(stdout, " %s ERROR: " format "\n", timestr, \ + ## __VA_ARGS__); \ + } \ + while (0) + + +#else // not __MINGW32__ + #include extern int use_tty; extern int use_syslog; @@ -146,11 +175,30 @@ extern int use_syslog; } } \ while (0) +#endif // if __MINGW32__ + #endif // if LIB_ONLY #endif // if __ANDROID__ +// Workaround for "%z" in Windows printf +#ifdef __MINGW32__ +#define SSIZE_FMT "%Id" +#define SIZE_FMT "%Iu" +#else +#define SSIZE_FMT "%zd" +#define SIZE_FMT "%zu" +#endif + +#ifdef __MINGW32__ +#ifdef ERROR +#undef ERROR +#endif +#define ERROR(s) ss_error(s) +void ss_error(const char *s); // Implemented in winsock.c +#else void ERROR(const char *s); +#endif char *ss_itoa(int i); int ss_isnumeric(const char *s); diff --git a/src/winsock.c b/src/winsock.c new file mode 100644 index 00000000..68a3af16 --- /dev/null +++ b/src/winsock.c @@ -0,0 +1,75 @@ +/* + * winsock.c - Windows socket compatibility layer + * + * Copyright (C) 2013 - 2018, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#ifdef __MINGW32__ + +#include "winsock.h" +#include "utils.h" + +void +winsock_init(void) +{ + int ret; + WSADATA wsa_data; + ret = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (ret != 0) { + FATAL("Failed to initialize winsock"); + } +} + +void +winsock_cleanup(void) +{ + WSACleanup(); +} + +int +setnonblocking(SOCKET socket) +{ + u_long arg = 1; + return ioctlsocket(socket, FIONBIO, &arg); +} + +void +ss_error(const char *s) +{ + char *msg = NULL; + DWORD err = WSAGetLastError(); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&msg, 0, NULL); + if (msg != NULL) { + // Remove trailing newline character + ssize_t len = strlen(msg) - 1; + if (len >= 0 && msg[len] == '\n') { + msg[len] = '\0'; + } + LOGE("%s: [%ld] %s", s, err, msg); + LocalFree(msg); + } +} + +#endif // __MINGW32__ diff --git a/src/winsock.h b/src/winsock.h new file mode 100644 index 00000000..a20259bb --- /dev/null +++ b/src/winsock.h @@ -0,0 +1,86 @@ +/* + * winsock.h - Windows socket compatibility layer + * + * Copyright (C) 2013 - 2018, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#ifndef _WINSOCK_H +#define _WINSOCK_H + +#ifdef __MINGW32__ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 +#undef _WIN32_WINNT +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + +#include +#include +#include + +// Override error number +#ifdef errno +#undef errno +#endif +#define errno WSAGetLastError() + +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif +#define EWOULDBLOCK WSAEWOULDBLOCK + +#ifdef CONNECT_IN_PROGRESS +#undef CONNECT_IN_PROGRESS +#endif +#define CONNECT_IN_PROGRESS WSAEWOULDBLOCK + +// Override close function +#define close(fd) closesocket(fd) + +// Override MinGW functions +#define setsockopt(a,b,c,d,e) setsockopt(a,b,c,(const char *)(d),e) +#define inet_ntop(a,b,c,d) inet_ntop(a,(void *)(b),c,d) + +// Override Windows built-in functions +#ifdef ERROR +#undef ERROR +#endif +#define ERROR(s) ss_error(s) +#ifndef _UTILS_H +void ss_error(const char *s); +#endif + +// Missing unistd.h functions +#define sleep(x) Sleep((x) * 1000) + +// Winsock compatibility functions +int setnonblocking(SOCKET socket); +void winsock_init(void); +void winsock_cleanup(void); + +#endif // __MINGW32__ + +#endif // _WINSOCK_H