Browse Source

Merge pull request #1978 from linusyang92/mingw-plugin

Support Plugins on Windows/MinGW
pull/1979/head
Max Lv 7 years ago
committed by GitHub
parent
commit
787b248d25
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 359 additions and 54 deletions
  1. 5
      README.md
  2. 4
      docker/mingw/Makefile
  3. 23
      docker/mingw/build.sh
  4. 4
      docker/mingw/make.bat
  5. 96
      src/local.c
  6. 60
      src/plugin.c
  7. 3
      src/plugin.h
  8. 90
      src/server.c
  9. 93
      src/tunnel.c
  10. 1
      src/utils.h
  11. 27
      src/winsock.c
  12. 7
      src/winsock.h

5
README.md

@ -354,10 +354,7 @@ Currently you need to use a patched libev library for MinGW:
* https://github.com/shadowsocks/libev/archive/mingw.zip * https://github.com/shadowsocks/libev/archive/mingw.zip
Notice that Windows (MinGW) version has some differences from other platforms:
1. No support of plugins at the moment.
2. TCP Fast Open (TFO) is only available on **Windows 10**, **1607** or later version (precisely, build >= 14393). If you are using **1709** (build 16299) or later version, you also need to run the following command in PowerShell/Command Prompt **as Administrator** and **reboot** to use TFO properly:
Notice that TCP Fast Open (TFO) is only available on **Windows 10**, **1607** or later version (precisely, build >= 14393). If you are using **1709** (build 16299) or later version, you also need to run the following command in PowerShell/Command Prompt **as Administrator** and **reboot** to use TFO properly:
netsh int tcp set global fastopenfallback=disabled netsh int tcp set global fastopenfallback=disabled

4
docker/mingw/Makefile

@ -20,6 +20,7 @@
REPO=shadowsocks REPO=shadowsocks
REV=master REV=master
PLUGIN=true
IMAGE=ss-build-mingw IMAGE=ss-build-mingw
DIST=ss-libev-win-dist.tar.gz DIST=ss-libev-win-dist.tar.gz
@ -28,7 +29,8 @@ all: build
build: build:
docker build --force-rm -t $(IMAGE) \ docker build --force-rm -t $(IMAGE) \
--build-arg REV=$(REV) --build-arg REPO=$(REPO) \ --build-arg REV=$(REV) --build-arg REPO=$(REPO) \
--build-arg REBUILD="$$(date +%Y-%m-%d-%H-%M-%S)" .
--build-arg REBUILD="$$(date +%Y-%m-%d-%H-%M-%S)" \
--build-arg PLUGIN=$(PLUGIN) .
docker run --rm --entrypoint cat $(IMAGE) /bin.tgz > $(DIST) docker run --rm --entrypoint cat $(IMAGE) /bin.tgz > $(DIST)
clean: clean:

23
docker/mingw/build.sh

@ -47,6 +47,25 @@ build_proj() {
make clean make clean
make LDFLAGS="-all-static -L${dep}/lib" make LDFLAGS="-all-static -L${dep}/lib"
make install-strip make install-strip
# Reference SIP003 plugin (Experimental)
[[ "${PLUGIN}" != "true" ]] && return 0
PLUGIN_URL=https://github.com/${PROJ_SITE}/simple-obfs.git
PLUGIN_REV=master
cd "$SRC"
git clone ${PLUGIN_URL} plugin
cd plugin
git checkout ${PLUGIN_REV}
git submodule update --init
./autogen.sh
./configure --host=${host} --prefix=${prefix} \
--disable-documentation \
--with-ev="$dep"
make clean
make LDFLAGS="-all-static -L${dep}/lib"
make install-strip
} }
dk_build() { dk_build() {
@ -65,6 +84,10 @@ dk_package() {
cp ${DIST}/i686/bin/ss-${bin}.exe ss-${bin}-x86.exe cp ${DIST}/i686/bin/ss-${bin}.exe ss-${bin}-x86.exe
cp ${DIST}/x86_64/bin/ss-${bin}.exe ss-${bin}-x64.exe cp ${DIST}/x86_64/bin/ss-${bin}.exe ss-${bin}-x64.exe
done done
for bin in local server; do
cp ${DIST}/i686/bin/obfs-${bin}.exe obfs-${bin}-x86.exe
cp ${DIST}/x86_64/bin/obfs-${bin}.exe obfs-${bin}-x64.exe
done
pushd "$SRC/proj" pushd "$SRC/proj"
GIT_REV="$(git rev-parse --short HEAD)" GIT_REV="$(git rev-parse --short HEAD)"
popd popd

4
docker/mingw/make.bat

@ -2,10 +2,12 @@
pushd %~dp0 pushd %~dp0
set "REPO=shadowsocks" set "REPO=shadowsocks"
set "REV=master" set "REV=master"
set "PLUGIN=true"
set "IMAGE=ss-build-mingw" set "IMAGE=ss-build-mingw"
set "DIST=ss-libev-win-dist.tar.gz" set "DIST=ss-libev-win-dist.tar.gz"
docker build --force-rm -t %IMAGE% ^ docker build --force-rm -t %IMAGE% ^
--build-arg REV=%REV% --build-arg REPO=%REPO% ^ --build-arg REV=%REV% --build-arg REPO=%REPO% ^
--build-arg REBUILD=%RANDOM% .
--build-arg REBUILD=%RANDOM% ^
--build-arg PLUGIN=%PLUGIN% .
docker run --rm --entrypoint cat %IMAGE% /bin.tgz > %DIST% docker run --rm --entrypoint cat %IMAGE% /bin.tgz > %DIST%
pause pause

96
src/local.c

@ -109,6 +109,13 @@ static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__ #ifndef __MINGW32__
static struct ev_signal sigchld_watcher; static struct ev_signal sigchld_watcher;
static struct ev_signal sigusr1_watcher; static struct ev_signal sigusr1_watcher;
#else
static struct plugin_watcher_t {
ev_io io;
SOCKET fd;
uint16_t port;
int valid;
} plugin_watcher;
#endif #endif
#ifdef HAVE_SETRLIMIT #ifdef HAVE_SETRLIMIT
@ -123,6 +130,9 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents);
static void remote_send_cb(EV_P_ ev_io *w, int revents); static void remote_send_cb(EV_P_ ev_io *w, int revents);
static void accept_cb(EV_P_ ev_io *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents);
static void signal_cb(EV_P_ ev_signal *w, int revents); static void signal_cb(EV_P_ ev_signal *w, int revents);
#if defined(__MINGW32__) && !defined(LIB_ONLY)
static void plugin_watcher_cb(EV_P_ ev_io *w, int revents);
#endif
static int create_and_bind(const char *addr, const char *port); static int create_and_bind(const char *addr, const char *port);
#ifdef HAVE_LAUNCHD #ifdef HAVE_LAUNCHD
@ -1312,6 +1322,8 @@ signal_cb(EV_P_ ev_signal *w, int revents)
#ifndef __MINGW32__ #ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ev_signal_stop(EV_DEFAULT, &sigusr1_watcher); ev_signal_stop(EV_DEFAULT, &sigusr1_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif #endif
keep_resolving = 0; keep_resolving = 0;
ev_unloop(EV_A_ EVUNLOOP_ALL); ev_unloop(EV_A_ EVUNLOOP_ALL);
@ -1319,6 +1331,27 @@ signal_cb(EV_P_ ev_signal *w, int revents)
} }
} }
#if defined(__MINGW32__) && !defined(LIB_ONLY)
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
{
char buf[1];
SOCKET fd = accept(plugin_watcher.fd, NULL, NULL);
if (fd == INVALID_SOCKET) {
return;
}
recv(fd, buf, 1, 0);
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
keep_resolving = 0;
ev_unloop(EV_A_ EVUNLOOP_ALL);
}
#endif
void void
accept_cb(EV_P_ ev_io *w, int revents) accept_cb(EV_P_ ev_io *w, int revents)
{ {
@ -1364,9 +1397,7 @@ main(int argc, char **argv)
char *plugin_opts = NULL; char *plugin_opts = NULL;
char *plugin_host = NULL; char *plugin_host = NULL;
char *plugin_port = NULL; char *plugin_port = NULL;
#ifndef __MINGW32__
char tmp_port[8]; char tmp_port[8];
#endif
srand(time(NULL)); srand(time(NULL));
@ -1596,7 +1627,6 @@ main(int argc, char **argv)
#endif #endif
if (plugin != NULL) { if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port(); uint16_t port = get_local_port();
if (port == 0) { if (port == 0) {
FATAL("failed to find a free port"); FATAL("failed to find a free port");
@ -1605,10 +1635,15 @@ main(int argc, char **argv)
plugin_host = "127.0.0.1"; plugin_host = "127.0.0.1";
plugin_port = tmp_port; plugin_port = tmp_port;
LOGI("plugin \"%s\" enabled", plugin);
#else
FATAL("plugins not implemented in MinGW port");
#ifdef __MINGW32__
memset(&plugin_watcher, 0, sizeof(plugin_watcher));
plugin_watcher.port = get_local_port();
if (plugin_watcher.port == 0) {
LOGE("failed to assign a control port for plugin");
}
#endif #endif
LOGI("plugin \"%s\" enabled", plugin);
} }
if (method == NULL) { if (method == NULL) {
@ -1658,7 +1693,40 @@ main(int argc, char **argv)
LOGI("resolving hostname to IPv6 address first"); LOGI("resolving hostname to IPv6 address first");
} }
#ifndef __MINGW32__
#ifdef __MINGW32__
// Listen on plugin control port
if (plugin != NULL && plugin_watcher.port != 0) {
SOCKET fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd != INVALID_SOCKET) {
plugin_watcher.valid = 0;
do {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(plugin_watcher.port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
LOGE("failed to bind plugin control port");
break;
}
if (listen(fd, 1)) {
LOGE("failed to listen on plugin control port");
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
closesocket(fd);
plugin_watcher.port = 0;
}
}
}
#endif
if (plugin != NULL) { if (plugin != NULL) {
int len = 0; int len = 0;
size_t buf_size = 256 * remote_num; size_t buf_size = 256 * remote_num;
@ -1671,12 +1739,16 @@ main(int argc, char **argv)
len = strlen(remote_str); len = strlen(remote_str);
} }
int err = start_plugin(plugin, plugin_opts, remote_str, int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port, MODE_CLIENT);
remote_port, plugin_host, plugin_port,
#ifdef __MINGW32__
plugin_watcher.port,
#endif
MODE_CLIENT);
if (err) { if (err) {
ERROR("start_plugin");
FATAL("failed to start the plugin"); FATAL("failed to start the plugin");
} }
} }
#endif
#ifndef __MINGW32__ #ifndef __MINGW32__
// ignore SIGPIPE // ignore SIGPIPE
@ -1800,11 +1872,9 @@ main(int argc, char **argv)
} }
// Clean up // Clean up
#ifndef __MINGW32__
if (plugin != NULL) { if (plugin != NULL) {
stop_plugin(); stop_plugin();
} }
#endif
if (mode != UDP_ONLY) { if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx.io); ev_io_stop(loop, &listen_ctx.io);
@ -1969,6 +2039,10 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
} }
#ifdef __MINGW32__ #ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup(); winsock_cleanup();
#endif #endif

60
src/plugin.c

@ -24,26 +24,38 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef __MINGW32__
#include <string.h> #include <string.h>
#ifndef __MINGW32__
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <netinet/in.h> #include <netinet/in.h>
#endif
#include <libcork/core.h> #include <libcork/core.h>
#include <libcork/os.h> #include <libcork/os.h>
#include "utils.h" #include "utils.h"
#include "plugin.h" #include "plugin.h"
#include "winsock.h"
#define CMD_RESRV_LEN 128 #define CMD_RESRV_LEN 128
#ifndef __MINGW32__
#define TEMPDIR "/tmp/"
#else
#define TEMPDIR
#endif
static int exit_code; static int exit_code;
static struct cork_env *env = NULL; static struct cork_env *env = NULL;
static struct cork_exec *exec = NULL; static struct cork_exec *exec = NULL;
static struct cork_subprocess *sub = NULL; static struct cork_subprocess *sub = NULL;
#ifdef __MINGW32__
static uint16_t sub_control_port = 0;
void cork_subprocess_set_control(struct cork_subprocess *self, uint16_t port);
#endif
static int static int
plugin_log__data(struct cork_stream_consumer *vself, plugin_log__data(struct cork_stream_consumer *vself,
@ -103,6 +115,9 @@ start_ss_plugin(const char *plugin,
cork_exec_set_env(exec, env); cork_exec_set_env(exec, env);
sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code); sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code);
#ifdef __MINGW32__
cork_subprocess_set_control(sub, sub_control_port);
#endif
return cork_subprocess_start(sub); return cork_subprocess_start(sub);
} }
@ -144,14 +159,19 @@ start_obfsproxy(const char *plugin,
enum plugin_mode mode) enum plugin_mode mode)
{ {
char *pch; char *pch;
char *opts_dump;
char *opts_dump = NULL;
char *buf = NULL; char *buf = NULL;
int ret, buf_size = 0; int ret, buf_size = 0;
opts_dump = strndup(plugin_opts, OBFSPROXY_OPTS_MAX);
if (!opts_dump) {
ERROR("start_obfsproxy strndup failed");
return -ENOMEM;
if (plugin_opts != NULL) {
opts_dump = strndup(plugin_opts, OBFSPROXY_OPTS_MAX);
if (!opts_dump) {
ERROR("start_obfsproxy strndup failed");
if (env != NULL) {
cork_env_free(env);
}
return -ENOMEM;
}
} }
exec = cork_exec_new(plugin); exec = cork_exec_new(plugin);
@ -162,17 +182,19 @@ start_obfsproxy(const char *plugin,
buf_size = 20 + strlen(plugin) + strlen(remote_host) buf_size = 20 + strlen(plugin) + strlen(remote_host)
+ strlen(remote_port) + strlen(local_host) + strlen(local_port); + strlen(remote_port) + strlen(local_host) + strlen(local_port);
buf = ss_malloc(buf_size); buf = ss_malloc(buf_size);
snprintf(buf, buf_size, "/tmp/%s_%s:%s_%s:%s", plugin,
snprintf(buf, buf_size, TEMPDIR "%s_%s:%s_%s:%s", plugin,
remote_host, remote_port, local_host, local_port); remote_host, remote_port, local_host, local_port);
cork_exec_add_param(exec, buf); cork_exec_add_param(exec, buf);
/* /*
* Iterate @plugin_opts by space * Iterate @plugin_opts by space
*/ */
pch = strtok(opts_dump, " ");
while (pch) {
cork_exec_add_param(exec, pch);
pch = strtok(NULL, " ");
if (opts_dump != NULL) {
pch = strtok(opts_dump, " ");
while (pch) {
cork_exec_add_param(exec, pch);
pch = strtok(NULL, " ");
}
} }
/* The rest options */ /* The rest options */
@ -193,8 +215,12 @@ start_obfsproxy(const char *plugin,
snprintf(buf, buf_size, "%s:%s", remote_host, remote_port); snprintf(buf, buf_size, "%s:%s", remote_host, remote_port);
cork_exec_add_param(exec, buf); cork_exec_add_param(exec, buf);
} }
cork_exec_set_env(exec, env); cork_exec_set_env(exec, env);
sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code); sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code);
#ifdef __MINGW32__
cork_subprocess_set_control(sub, sub_control_port);
#endif
ret = cork_subprocess_start(sub); ret = cork_subprocess_start(sub);
ss_free(opts_dump); ss_free(opts_dump);
free(buf); free(buf);
@ -208,11 +234,16 @@ start_plugin(const char *plugin,
const char *remote_port, const char *remote_port,
const char *local_host, const char *local_host,
const char *local_port, const char *local_port,
#ifdef __MINGW32__
uint16_t control_port,
#endif
enum plugin_mode mode) enum plugin_mode mode)
{ {
#ifndef __MINGW32__
char *new_path = NULL; char *new_path = NULL;
const char *current_path; const char *current_path;
size_t new_path_len; size_t new_path_len;
#endif
int ret; int ret;
if (plugin == NULL) if (plugin == NULL)
@ -221,6 +252,7 @@ start_plugin(const char *plugin,
if (strlen(plugin) == 0) if (strlen(plugin) == 0)
return 0; return 0;
#ifndef __MINGW32__
/* /*
* Add current dir to PATH, so we can search plugin in current dir * Add current dir to PATH, so we can search plugin in current dir
*/ */
@ -244,6 +276,9 @@ start_plugin(const char *plugin,
} }
if (new_path != NULL) if (new_path != NULL)
cork_env_add(env, "PATH", new_path); cork_env_add(env, "PATH", new_path);
#else
sub_control_port = control_port;
#endif
if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy"))) if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy")))
ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port, ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port,
@ -251,7 +286,9 @@ start_plugin(const char *plugin,
else else
ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port, ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode); local_host, local_port, mode);
#ifndef __MINGW32__
ss_free(new_path); ss_free(new_path);
#endif
env = NULL; env = NULL;
return ret; return ret;
} }
@ -302,4 +339,3 @@ is_plugin_running()
return 0; return 0;
} }
#endif

3
src/plugin.h

@ -69,6 +69,9 @@ int start_plugin(const char *plugin,
const char *remote_port, const char *remote_port,
const char *local_host, const char *local_host,
const char *local_port, const char *local_port,
#ifdef __MINGW32__
uint16_t control_port,
#endif
enum plugin_mode mode); enum plugin_mode mode);
uint16_t get_local_port(); uint16_t get_local_port();
void stop_plugin(); void stop_plugin();

90
src/server.c

@ -145,6 +145,13 @@ static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher; static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__ #ifndef __MINGW32__
static struct ev_signal sigchld_watcher; static struct ev_signal sigchld_watcher;
#else
static struct plugin_watcher_t {
ev_io io;
SOCKET fd;
uint16_t port;
int valid;
} plugin_watcher;
#endif #endif
static struct cork_dllist connections; static struct cork_dllist connections;
@ -1509,12 +1516,34 @@ signal_cb(EV_P_ ev_signal *w, int revents)
ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__ #ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif #endif
ev_unloop(EV_A_ EVUNLOOP_ALL); ev_unloop(EV_A_ EVUNLOOP_ALL);
} }
} }
} }
#ifdef __MINGW32__
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
{
char buf[1];
SOCKET fd = accept(plugin_watcher.fd, NULL, NULL);
if (fd == INVALID_SOCKET) {
return;
}
recv(fd, buf, 1, 0);
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
ev_unloop(EV_A_ EVUNLOOP_ALL);
}
#endif
static void static void
accept_cb(EV_P_ ev_io *w, int revents) accept_cb(EV_P_ ev_io *w, int revents)
{ {
@ -1584,9 +1613,7 @@ main(int argc, char **argv)
char *server_port = NULL; char *server_port = NULL;
char *plugin_opts = NULL; char *plugin_opts = NULL;
char *plugin_port = NULL; char *plugin_port = NULL;
#ifndef __MINGW32__
char tmp_port[8]; char tmp_port[8];
#endif
int server_num = 0; int server_num = 0;
const char *server_host[MAX_REMOTE_NUM]; const char *server_host[MAX_REMOTE_NUM];
@ -1815,7 +1842,6 @@ main(int argc, char **argv)
#endif #endif
if (plugin != NULL) { if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port(); uint16_t port = get_local_port();
if (port == 0) { if (port == 0) {
FATAL("failed to find a free port"); FATAL("failed to find a free port");
@ -1823,8 +1849,13 @@ main(int argc, char **argv)
snprintf(tmp_port, 8, "%d", port); snprintf(tmp_port, 8, "%d", port);
plugin_port = server_port; plugin_port = server_port;
server_port = tmp_port; server_port = tmp_port;
#else
FATAL("plugins not implemented in MinGW port");
#ifdef __MINGW32__
memset(&plugin_watcher, 0, sizeof(plugin_watcher));
plugin_watcher.port = get_local_port();
if (plugin_watcher.port == 0) {
LOGE("failed to assign a control port for plugin");
}
#endif #endif
} }
@ -1913,7 +1944,40 @@ main(int argc, char **argv)
if (nameservers != NULL) if (nameservers != NULL)
LOGI("using nameserver: %s", nameservers); LOGI("using nameserver: %s", nameservers);
#ifndef __MINGW32__
#ifdef __MINGW32__
// Listen on plugin control port
if (plugin != NULL && plugin_watcher.port != 0) {
SOCKET fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd != INVALID_SOCKET) {
plugin_watcher.valid = 0;
do {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(plugin_watcher.port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
LOGE("failed to bind plugin control port");
break;
}
if (listen(fd, 1)) {
LOGE("failed to listen on plugin control port");
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
closesocket(fd);
plugin_watcher.port = 0;
}
}
}
#endif
// Start plugin server // Start plugin server
if (plugin != NULL) { if (plugin != NULL) {
int len = 0; int len = 0;
@ -1928,12 +1992,16 @@ main(int argc, char **argv)
} }
int err = start_plugin(plugin, plugin_opts, server_str, int err = start_plugin(plugin, plugin_opts, server_str,
plugin_port, "127.0.0.1", server_port, MODE_SERVER);
plugin_port, "127.0.0.1", server_port,
#ifdef __MINGW32__
plugin_watcher.port,
#endif
MODE_SERVER);
if (err) { if (err) {
ERROR("start_plugin");
FATAL("failed to start the plugin"); FATAL("failed to start the plugin");
} }
} }
#endif
// initialize listen context // initialize listen context
listen_ctx_t listen_ctx_list[server_num]; listen_ctx_t listen_ctx_list[server_num];
@ -2040,11 +2108,9 @@ main(int argc, char **argv)
ev_timer_stop(EV_DEFAULT, &block_list_watcher); ev_timer_stop(EV_DEFAULT, &block_list_watcher);
#ifndef __MINGW32__
if (plugin != NULL) { if (plugin != NULL) {
stop_plugin(); stop_plugin();
} }
#endif
// Clean up // Clean up
@ -2069,6 +2135,10 @@ main(int argc, char **argv)
} }
#ifdef __MINGW32__ #ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup(); winsock_cleanup();
#endif #endif

93
src/tunnel.c

@ -102,6 +102,13 @@ static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher; static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__ #ifndef __MINGW32__
static struct ev_signal sigchld_watcher; static struct ev_signal sigchld_watcher;
#else
static struct plugin_watcher_t {
ev_io io;
SOCKET fd;
uint16_t port;
int valid;
} plugin_watcher;
#endif #endif
#ifndef __MINGW32__ #ifndef __MINGW32__
@ -759,6 +766,8 @@ signal_cb(EV_P_ ev_signal *w, int revents)
ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__ #ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif #endif
keep_resolving = 0; keep_resolving = 0;
ev_unloop(EV_A_ EVUNLOOP_ALL); ev_unloop(EV_A_ EVUNLOOP_ALL);
@ -766,6 +775,27 @@ signal_cb(EV_P_ ev_signal *w, int revents)
} }
} }
#ifdef __MINGW32__
static void
plugin_watcher_cb(EV_P_ ev_io *w, int revents)
{
char buf[1];
SOCKET fd = accept(plugin_watcher.fd, NULL, NULL);
if (fd == INVALID_SOCKET) {
return;
}
recv(fd, buf, 1, 0);
closesocket(fd);
LOGE("plugin service exit unexpectedly");
ret_val = -1;
ev_signal_stop(EV_DEFAULT, &sigint_watcher);
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
keep_resolving = 0;
ev_unloop(EV_A_ EVUNLOOP_ALL);
}
#endif
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -790,9 +820,7 @@ main(int argc, char **argv)
char *plugin_opts = NULL; char *plugin_opts = NULL;
char *plugin_host = NULL; char *plugin_host = NULL;
char *plugin_port = NULL; char *plugin_port = NULL;
#ifndef __MINGW32__
char tmp_port[8]; char tmp_port[8];
#endif
int remote_num = 0; int remote_num = 0;
ss_addr_t remote_addr[MAX_REMOTE_NUM]; ss_addr_t remote_addr[MAX_REMOTE_NUM];
@ -1012,7 +1040,6 @@ main(int argc, char **argv)
#endif #endif
if (plugin != NULL) { if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port(); uint16_t port = get_local_port();
if (port == 0) { if (port == 0) {
FATAL("failed to find a free port"); FATAL("failed to find a free port");
@ -1021,10 +1048,15 @@ main(int argc, char **argv)
plugin_host = "127.0.0.1"; plugin_host = "127.0.0.1";
plugin_port = tmp_port; plugin_port = tmp_port;
LOGI("plugin \"%s\" enabled", plugin);
#else
FATAL("plugins not implemented in MinGW port");
#ifdef __MINGW32__
memset(&plugin_watcher, 0, sizeof(plugin_watcher));
plugin_watcher.port = get_local_port();
if (plugin_watcher.port == 0) {
LOGE("failed to assign a control port for plugin");
}
#endif #endif
LOGI("plugin \"%s\" enabled", plugin);
} }
if (method == NULL) { if (method == NULL) {
@ -1068,7 +1100,40 @@ main(int argc, char **argv)
FATAL("tunnel port is not defined"); FATAL("tunnel port is not defined");
} }
#ifndef __MINGW32__
#ifdef __MINGW32__
// Listen on plugin control port
if (plugin != NULL && plugin_watcher.port != 0) {
SOCKET fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd != INVALID_SOCKET) {
plugin_watcher.valid = 0;
do {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(plugin_watcher.port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
LOGE("failed to bind plugin control port");
break;
}
if (listen(fd, 1)) {
LOGE("failed to listen on plugin control port");
break;
}
plugin_watcher.fd = fd;
ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ);
ev_io_start(EV_DEFAULT, &plugin_watcher.io);
plugin_watcher.valid = 1;
} while (0);
if (!plugin_watcher.valid) {
closesocket(fd);
plugin_watcher.port = 0;
}
}
}
#endif
if (plugin != NULL) { if (plugin != NULL) {
int len = 0; int len = 0;
size_t buf_size = 256 * remote_num; size_t buf_size = 256 * remote_num;
@ -1080,12 +1145,16 @@ main(int argc, char **argv)
len = strlen(remote_str); len = strlen(remote_str);
} }
int err = start_plugin(plugin, plugin_opts, remote_str, int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port, MODE_CLIENT);
remote_port, plugin_host, plugin_port,
#ifdef __MINGW32__
plugin_watcher.port,
#endif
MODE_CLIENT);
if (err) { if (err) {
ERROR("start_plugin");
FATAL("failed to start the plugin"); FATAL("failed to start the plugin");
} }
} }
#endif
#ifndef __MINGW32__ #ifndef __MINGW32__
// ignore SIGPIPE // ignore SIGPIPE
@ -1190,13 +1259,15 @@ main(int argc, char **argv)
ev_run(loop, 0); ev_run(loop, 0);
#ifndef __MINGW32__
if (plugin != NULL) { if (plugin != NULL) {
stop_plugin(); stop_plugin();
} }
#endif
#ifdef __MINGW32__ #ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup(); winsock_cleanup();
#endif #endif

1
src/utils.h

@ -191,6 +191,7 @@ extern int use_syslog;
#endif #endif
#ifdef __MINGW32__ #ifdef __MINGW32__
// Override Windows built-in functions
#ifdef ERROR #ifdef ERROR
#undef ERROR #undef ERROR
#endif #endif

27
src/winsock.c

@ -25,6 +25,31 @@
#include "winsock.h" #include "winsock.h"
#include "utils.h" #include "utils.h"
#ifndef ENABLE_QUICK_EDIT
#define ENABLE_QUICK_EDIT 0x0040
#endif
#ifndef STD_INPUT_HANDLE
#define STD_INPUT_HANDLE ((DWORD)-10)
#endif
static void
disable_quick_edit(void)
{
DWORD mode = 0;
HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
// Get current console mode
if (console == NULL || !GetConsoleMode(console, &mode)) {
return;
}
// Clear the quick edit bit in the mode flags
mode &= ~ENABLE_QUICK_EDIT;
mode |= ENABLE_EXTENDED_FLAGS;
SetConsoleMode(console, mode);
}
void void
winsock_init(void) winsock_init(void)
{ {
@ -34,6 +59,8 @@ winsock_init(void)
if (ret != 0) { if (ret != 0) {
FATAL("Failed to initialize winsock"); FATAL("Failed to initialize winsock");
} }
// Disable quick edit mode to prevent stuck
disable_quick_edit();
} }
void void

7
src/winsock.h

@ -97,12 +97,11 @@
#undef ERROR #undef ERROR
#endif #endif
#define ERROR(s) ss_error(s) #define ERROR(s) ss_error(s)
#ifndef _UTILS_H
void ss_error(const char *s);
#endif
// Missing unistd.h functions
// Missing Unix functions
#define sleep(x) Sleep((x) * 1000) #define sleep(x) Sleep((x) * 1000)
#define bzero(s,n) memset(s,0,n)
#define strndup(s,n) ss_strndup(s,n)
// Winsock compatibility functions // Winsock compatibility functions
int setnonblocking(SOCKET socket); int setnonblocking(SOCKET socket);

Loading…
Cancel
Save