Browse Source

Enable plugins on MinGW

pull/1978/head
Linus Yang 7 years ago
parent
commit
14fb82b966
8 changed files with 329 additions and 48 deletions
  1. 96
      src/local.c
  2. 60
      src/plugin.c
  3. 3
      src/plugin.h
  4. 90
      src/server.c
  5. 93
      src/tunnel.c
  6. 1
      src/utils.h
  7. 27
      src/winsock.c
  8. 7
      src/winsock.h

96
src/local.c

@ -109,6 +109,13 @@ static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__
static struct ev_signal sigchld_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
#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 accept_cb(EV_P_ ev_io *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);
#ifdef HAVE_LAUNCHD
@ -1312,6 +1322,8 @@ signal_cb(EV_P_ ev_signal *w, int revents)
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
ev_signal_stop(EV_DEFAULT, &sigusr1_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif
keep_resolving = 0;
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
accept_cb(EV_P_ ev_io *w, int revents)
{
@ -1364,9 +1397,7 @@ 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));
@ -1596,7 +1627,6 @@ main(int argc, char **argv)
#endif
if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port();
if (port == 0) {
FATAL("failed to find a free port");
@ -1605,10 +1635,15 @@ main(int argc, char **argv)
plugin_host = "127.0.0.1";
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
LOGI("plugin \"%s\" enabled", plugin);
}
if (method == NULL) {
@ -1658,7 +1693,40 @@ main(int argc, char **argv)
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) {
int len = 0;
size_t buf_size = 256 * remote_num;
@ -1671,12 +1739,16 @@ main(int argc, char **argv)
len = strlen(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) {
ERROR("start_plugin");
FATAL("failed to start the plugin");
}
}
#endif
#ifndef __MINGW32__
// ignore SIGPIPE
@ -1800,11 +1872,9 @@ 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);
@ -1969,6 +2039,10 @@ _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udat
}
#ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup();
#endif

60
src/plugin.c

@ -24,26 +24,38 @@
#include "config.h"
#endif
#ifndef __MINGW32__
#include <string.h>
#ifndef __MINGW32__
#include <unistd.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#endif
#include <libcork/core.h>
#include <libcork/os.h>
#include "utils.h"
#include "plugin.h"
#include "winsock.h"
#define CMD_RESRV_LEN 128
#ifndef __MINGW32__
#define TEMPDIR "/tmp/"
#else
#define TEMPDIR
#endif
static int exit_code;
static struct cork_env *env = NULL;
static struct cork_exec *exec = 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
plugin_log__data(struct cork_stream_consumer *vself,
@ -103,6 +115,9 @@ start_ss_plugin(const char *plugin,
cork_exec_set_env(exec, env);
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);
}
@ -144,14 +159,19 @@ start_obfsproxy(const char *plugin,
enum plugin_mode mode)
{
char *pch;
char *opts_dump;
char *opts_dump = NULL;
char *buf = NULL;
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);
@ -162,17 +182,19 @@ start_obfsproxy(const char *plugin,
buf_size = 20 + strlen(plugin) + strlen(remote_host)
+ strlen(remote_port) + strlen(local_host) + strlen(local_port);
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);
cork_exec_add_param(exec, buf);
/*
* 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 */
@ -193,8 +215,12 @@ start_obfsproxy(const char *plugin,
snprintf(buf, buf_size, "%s:%s", remote_host, remote_port);
cork_exec_add_param(exec, buf);
}
cork_exec_set_env(exec, env);
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);
ss_free(opts_dump);
free(buf);
@ -208,11 +234,16 @@ start_plugin(const char *plugin,
const char *remote_port,
const char *local_host,
const char *local_port,
#ifdef __MINGW32__
uint16_t control_port,
#endif
enum plugin_mode mode)
{
#ifndef __MINGW32__
char *new_path = NULL;
const char *current_path;
size_t new_path_len;
#endif
int ret;
if (plugin == NULL)
@ -221,6 +252,7 @@ start_plugin(const char *plugin,
if (strlen(plugin) == 0)
return 0;
#ifndef __MINGW32__
/*
* 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)
cork_env_add(env, "PATH", new_path);
#else
sub_control_port = control_port;
#endif
if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy")))
ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port,
@ -251,7 +286,9 @@ start_plugin(const char *plugin,
else
ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode);
#ifndef __MINGW32__
ss_free(new_path);
#endif
env = NULL;
return ret;
}
@ -302,4 +339,3 @@ is_plugin_running()
return 0;
}
#endif

3
src/plugin.h

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

90
src/server.c

@ -145,6 +145,13 @@ static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__
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
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);
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif
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
accept_cb(EV_P_ ev_io *w, int revents)
{
@ -1584,9 +1613,7 @@ 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];
@ -1815,7 +1842,6 @@ main(int argc, char **argv)
#endif
if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port();
if (port == 0) {
FATAL("failed to find a free port");
@ -1823,8 +1849,13 @@ 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");
#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
}
@ -1913,7 +1944,40 @@ main(int argc, char **argv)
if (nameservers != NULL)
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
if (plugin != NULL) {
int len = 0;
@ -1928,12 +1992,16 @@ main(int argc, char **argv)
}
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) {
ERROR("start_plugin");
FATAL("failed to start the plugin");
}
}
#endif
// initialize listen context
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);
#ifndef __MINGW32__
if (plugin != NULL) {
stop_plugin();
}
#endif
// Clean up
@ -2069,6 +2135,10 @@ main(int argc, char **argv)
}
#ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup();
#endif

93
src/tunnel.c

@ -102,6 +102,13 @@ static struct ev_signal sigint_watcher;
static struct ev_signal sigterm_watcher;
#ifndef __MINGW32__
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
#ifndef __MINGW32__
@ -759,6 +766,8 @@ signal_cb(EV_P_ ev_signal *w, int revents)
ev_signal_stop(EV_DEFAULT, &sigterm_watcher);
#ifndef __MINGW32__
ev_signal_stop(EV_DEFAULT, &sigchld_watcher);
#else
ev_io_stop(EV_DEFAULT, &plugin_watcher.io);
#endif
keep_resolving = 0;
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
main(int argc, char **argv)
{
@ -790,9 +820,7 @@ 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];
@ -1012,7 +1040,6 @@ main(int argc, char **argv)
#endif
if (plugin != NULL) {
#ifndef __MINGW32__
uint16_t port = get_local_port();
if (port == 0) {
FATAL("failed to find a free port");
@ -1021,10 +1048,15 @@ main(int argc, char **argv)
plugin_host = "127.0.0.1";
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
LOGI("plugin \"%s\" enabled", plugin);
}
if (method == NULL) {
@ -1068,7 +1100,40 @@ main(int argc, char **argv)
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) {
int len = 0;
size_t buf_size = 256 * remote_num;
@ -1080,12 +1145,16 @@ main(int argc, char **argv)
len = strlen(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) {
ERROR("start_plugin");
FATAL("failed to start the plugin");
}
}
#endif
#ifndef __MINGW32__
// ignore SIGPIPE
@ -1190,13 +1259,15 @@ main(int argc, char **argv)
ev_run(loop, 0);
#ifndef __MINGW32__
if (plugin != NULL) {
stop_plugin();
}
#endif
#ifdef __MINGW32__
if (plugin_watcher.valid) {
closesocket(plugin_watcher.fd);
}
winsock_cleanup();
#endif

1
src/utils.h

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

27
src/winsock.c

@ -25,6 +25,31 @@
#include "winsock.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
winsock_init(void)
{
@ -34,6 +59,8 @@ winsock_init(void)
if (ret != 0) {
FATAL("Failed to initialize winsock");
}
// Disable quick edit mode to prevent stuck
disable_quick_edit();
}
void

7
src/winsock.h

@ -97,12 +97,11 @@
#undef ERROR
#endif
#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 bzero(s,n) memset(s,0,n)
#define strndup(s,n) ss_strndup(s,n)
// Winsock compatibility functions
int setnonblocking(SOCKET socket);

Loading…
Cancel
Save