From 21b9258d7778647e8ecd799db10efc2c6c0052fe Mon Sep 17 00:00:00 2001 From: Linus Yang Date: Mon, 9 Sep 2013 20:59:22 +0800 Subject: [PATCH] Add initial support for native win32 platform Should be built against MinGW, and please note that only ss-local is ported due to lack win32 support of libasyncns. And libev doesn't support IOCP but only supports select --- .gitignore | 6 +++ Makefile.am | 4 ++ Makefile.in | 5 ++- README.md | 24 ++++++++++- config.h.in | 21 +++++++++ configure | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 54 +++++++++++++++++++++++ src/Makefile.am | 11 ++++- src/Makefile.in | 44 +++++++++++++------ src/encrypt.h | 13 ++++++ src/jconf.c | 4 ++ src/local.c | 48 ++++++++++++++------- src/udprelay.c | 25 +++++++---- src/udprelay.h | 2 +- src/utils.c | 11 +++-- src/utils.h | 45 ++++++++++++++++++- src/win32.c | 75 ++++++++++++++++++++++++++++++++ src/win32.h | 33 ++++++++++++++ 18 files changed, 490 insertions(+), 47 deletions(-) create mode 100644 src/win32.c create mode 100644 src/win32.h diff --git a/.gitignore b/.gitignore index ecc68951..8fe3a346 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,12 @@ debian/files debian/shadowsocks.substvars debian/*.debhelper* +# Ignore garbage of OS X +*.DS_Store + +# Ignore vim cache +*.swp + # Do not edit the following section # Edit Compile Debug Document Distribute *~ diff --git a/Makefile.am b/Makefile.am index a6fe7ae8..36cc1e30 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,7 @@ +if BUILD_WINCOMPAT +SUBDIRS = libev src +else SUBDIRS = libasyncns libev src +endif ACLOCAL_AMFLAGS = -I m4 man_MANS = shadowsocks.8 diff --git a/Makefile.in b/Makefile.in index ae36ce5d..216d1947 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,7 +100,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) +DIST_SUBDIRS = libasyncns libev src DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -259,7 +259,8 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = libasyncns libev src +@BUILD_WINCOMPAT_FALSE@SUBDIRS = libasyncns libev src +@BUILD_WINCOMPAT_TRUE@SUBDIRS = libev src ACLOCAL_AMFLAGS = -I m4 man_MANS = shadowsocks.8 all: config.h diff --git a/README.md b/README.md index e6a1df2a..e17e38c1 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,8 @@ no more than 5% on a low-end router (Buffalo WHR-G300N V2 with a 400MHz MIPS CPU Installation ------------ -Build the binary like this: +For Unix-like systems, especially Debian-based systems, +e.g. Ubuntu, Debian or Linux Mint, you can build the binary like this: ```bash sudo apt-get install build-essential autoconf libtool libssl-dev @@ -72,6 +73,27 @@ Build the binary like this: sudo make install ``` +For Windows, use either MinGW (msys) or Cygwin to build. +At the moment, only `ss-local` is supported to build against MinGW (msys). + +If you are using MinGW (msys), please download OpenSSL source tarball +to the home directory of msys, and build it like this (may take a few minutes): + +```bash + tar zxf openssl-1.0.1e.tar.gz + cd openssl-1.0.1e + ./config --prefix="$HOME/prebuilt" --openssldir="$HOME/prebuilt/openssl" + make && make install +``` + +Then, build the binary using the commands below, and all `.exe` files +will be built at `$HOME/ss/bin`: + +```bash + ./configure --prefix="$HOME/ss" --with-openssl="$HOME/prebuilt" + make && make install +``` + Usage ----- diff --git a/config.h.in b/config.h.in index c0aea8e2..f53bea41 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,18 @@ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD +/* Override libev default fd conversion macro. */ +#undef EV_FD_TO_WIN32_HANDLE + +/* Override libev default fd close macro. */ +#undef EV_WIN32_CLOSE_FD + +/* Override libev default handle conversion macro. */ +#undef EV_WIN32_HANDLE_TO_FD + +/* Reset max file descriptor size. */ +#undef FD_SETSIZE + /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H @@ -193,12 +205,21 @@ /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINSOCK2_H + /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK +/* Define to 1 if you have the header file. */ +#undef HAVE_WS2TCPIP_H + /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR diff --git a/configure b/configure index b620c05b..f8db85d3 100755 --- a/configure +++ b/configure @@ -621,6 +621,8 @@ PTHREAD_LIBS PTHREAD_CC acx_pthread_config LIBOBJS +BUILD_WINCOMPAT_FALSE +BUILD_WINCOMPAT_TRUE BUILD_REDIRECTOR_FALSE BUILD_REDIRECTOR_TRUE INET_NTOP_LIB @@ -12709,6 +12711,14 @@ fi +case $host in + *-mingw*) + LIBS="$LIBS -lgdi32 -lws2_32" + ;; + *) + ;; +esac + @@ -13007,6 +13017,24 @@ case $host in { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux" >&5 $as_echo "Linux" >&6; } ;; + *-mingw*) + +$as_echo "#define FD_SETSIZE 2048" >>confdefs.h + + +$as_echo "#define EV_FD_TO_WIN32_HANDLE(fd) (fd)" >>confdefs.h + + +$as_echo "#define EV_WIN32_HANDLE_TO_FD(handle) (handle)" >>confdefs.h + + +$as_echo "#define EV_WIN32_CLOSE_FD(fd) closesocket(fd)" >>confdefs.h + + + os_support=mingw + { $as_echo "$as_me:${as_lineno-$LINENO}: result: MinGW" >&5 +$as_echo "MinGW" >&6; } + ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: transparent proxy does not support for $host" >&5 $as_echo "transparent proxy does not support for $host" >&6; } @@ -13021,6 +13049,14 @@ else BUILD_REDIRECTOR_FALSE= fi + if test "$os_support" = "mingw"; then + BUILD_WINCOMPAT_TRUE= + BUILD_WINCOMPAT_FALSE='#' +else + BUILD_WINCOMPAT_TRUE='#' + BUILD_WINCOMPAT_FALSE= +fi + for ac_header in stdint.h inttypes.h arpa/inet.h fcntl.h langinfo.h locale.h netdb.h netinet/in.h stdlib.h string.h strings.h unistd.h sys/ioctl.h do : @@ -13036,6 +13072,29 @@ fi done +case $host in + *-mingw*) + for ac_header in windows.h winsock2.h ws2tcpip.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + as_fn_error $? "Missing MinGW headers" "$LINENO" 5 +fi + +done + + ;; + *) + # These are POSIX-like systems using BSD-like sockets API. + ;; +esac + for ac_header in sys/socket.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" @@ -14106,6 +14165,55 @@ fi done +if test "$ac_cv_func_select" != "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for select in ws2_32" >&5 +$as_echo_n "checking for select in ws2_32... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_WINSOCK2_H +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +int +main () +{ + + select(0,(fd_set *)NULL,(fd_set *)NULL,(fd_set *)NULL,(struct timeval *)NULL); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_SELECT="1" + +cat >>confdefs.h <<_ACEOF +#define HAVE_SELECT 1 +_ACEOF + + HAVE_SYS_SELECT_H="1" + +cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_SELECT_H 1 +_ACEOF + + +else + + as_fn_error $? "no" "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; @@ -14860,6 +14968,10 @@ if test -z "${BUILD_REDIRECTOR_TRUE}" && test -z "${BUILD_REDIRECTOR_FALSE}"; th as_fn_error $? "conditional \"BUILD_REDIRECTOR\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${BUILD_WINCOMPAT_TRUE}" && test -z "${BUILD_WINCOMPAT_FALSE}"; then + as_fn_error $? "conditional \"BUILD_WINCOMPAT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" diff --git a/configure.ac b/configure.ac index 7c26973d..d87cdf63 100755 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,15 @@ AM_PROG_CC_C_O dnl Checks for libev m4_include([libev/libev.m4]) +dnl Add library for mingw +case $host in + *-mingw*) + LIBS="$LIBS -lgdi32 -lws2_32" + ;; + *) + ;; +esac + dnl Checks for openssl ss_OPENSSL @@ -34,16 +43,36 @@ case $host in os_support=linux AC_MSG_RESULT(Linux) ;; + *-mingw*) + dnl Add custom macros for libev + AC_DEFINE([FD_SETSIZE], [2048], [Reset max file descriptor size.]) + AC_DEFINE([EV_FD_TO_WIN32_HANDLE(fd)], [(fd)], [Override libev default fd conversion macro.]) + AC_DEFINE([EV_WIN32_HANDLE_TO_FD(handle)], [(handle)], [Override libev default handle conversion macro.]) + AC_DEFINE([EV_WIN32_CLOSE_FD(fd)], [closesocket(fd)], [Override libev default fd close macro.]) + + os_support=mingw + AC_MSG_RESULT(MinGW) + ;; *) AC_MSG_RESULT(transparent proxy does not support for $host) ;; esac AM_CONDITIONAL(BUILD_REDIRECTOR, test "$os_support" = "linux") +AM_CONDITIONAL(BUILD_WINCOMPAT, test "$os_support" = "mingw") dnl Checks for header files. AC_CHECK_HEADERS([stdint.h inttypes.h arpa/inet.h fcntl.h langinfo.h locale.h netdb.h netinet/in.h stdlib.h string.h strings.h unistd.h sys/ioctl.h]) +case $host in + *-mingw*) + AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h], [], [AC_MSG_ERROR([Missing MinGW headers])], []) + ;; + *) + # These are POSIX-like systems using BSD-like sockets API. + ;; +esac + dnl A special check required for on Darwin. See dnl http://www.gnu.org/software/autoconf/manual/html_node/Header-Portability.html. AC_CHECK_HEADERS([sys/socket.h]) @@ -90,6 +119,31 @@ AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_CHECK_FUNCS([memset select setresuid setreuid strerror]) +dnl Check for select() into ws2_32 for Msys/Mingw +if test "$ac_cv_func_select" != "yes"; then + AC_MSG_CHECKING([for select in ws2_32]) + AC_TRY_LINK([ +#ifdef HAVE_WINSOCK2_H +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + ],[ + select(0,(fd_set *)NULL,(fd_set *)NULL,(fd_set *)NULL,(struct timeval *)NULL); + ],[ + AC_MSG_RESULT([yes]) + HAVE_SELECT="1" + AC_DEFINE_UNQUOTED(HAVE_SELECT, 1, + [Define to 1 if you have the `select' function.]) + HAVE_SYS_SELECT_H="1" + AC_DEFINE_UNQUOTED(HAVE_SYS_SELECT_H, 1, + [Define to 1 if you have the header file.]) + ],[ + AC_MSG_ERROR([no]) + ]) +fi + AC_SYS_LARGEFILE AC_CHECK_LIB(socket, connect) diff --git a/src/Makefile.am b/src/Makefile.am index acce1f62..915210e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,12 @@ AM_LDFLAGS = -static SS_COMMON_LIBS = $(top_builddir)/libev/libev.la $(INET_NTOP_LIB) -bin_PROGRAMS = ss-local ss-server +bin_PROGRAMS = ss-local + +if !BUILD_WINCOMPAT +bin_PROGRAMS += ss-server +endif + ss_local_SOURCES = utils.c \ jconf.c \ json.c \ @@ -28,6 +33,10 @@ ss_server_LDADD += $(top_builddir)/libasyncns/libasyncns.la ss_local_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL ss_server_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_REMOTE +if BUILD_WINCOMPAT +ss_local_SOURCES += win32.c +endif + if BUILD_REDIRECTOR bin_PROGRAMS += ss-redir ss_redir_SOURCES = utils.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 84cb8ec0..a33766bf 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -34,8 +34,10 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -bin_PROGRAMS = ss-local$(EXEEXT) ss-server$(EXEEXT) $(am__EXEEXT_1) -@BUILD_REDIRECTOR_TRUE@am__append_1 = ss-redir +bin_PROGRAMS = ss-local$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) +@BUILD_WINCOMPAT_FALSE@am__append_1 = ss-server +@BUILD_WINCOMPAT_TRUE@am__append_2 = win32.c +@BUILD_REDIRECTOR_TRUE@am__append_3 = ss-redir subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -51,13 +53,18 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -@BUILD_REDIRECTOR_TRUE@am__EXEEXT_1 = ss-redir$(EXEEXT) +@BUILD_WINCOMPAT_FALSE@am__EXEEXT_1 = ss-server$(EXEEXT) +@BUILD_REDIRECTOR_TRUE@am__EXEEXT_2 = ss-redir$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) +am__ss_local_SOURCES_DIST = utils.c jconf.c json.c encrypt.c \ + udprelay.c cache.c local.c win32.c +@BUILD_WINCOMPAT_TRUE@am__objects_1 = ss_local-win32.$(OBJEXT) am_ss_local_OBJECTS = ss_local-utils.$(OBJEXT) \ ss_local-jconf.$(OBJEXT) ss_local-json.$(OBJEXT) \ ss_local-encrypt.$(OBJEXT) ss_local-udprelay.$(OBJEXT) \ - ss_local-cache.$(OBJEXT) ss_local-local.$(OBJEXT) + ss_local-cache.$(OBJEXT) ss_local-local.$(OBJEXT) \ + $(am__objects_1) ss_local_OBJECTS = $(am_ss_local_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(top_builddir)/libev/libev.la \ @@ -96,8 +103,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(ss_local_SOURCES) $(ss_redir_SOURCES) $(ss_server_SOURCES) -DIST_SOURCES = $(ss_local_SOURCES) $(am__ss_redir_SOURCES_DIST) \ - $(ss_server_SOURCES) +DIST_SOURCES = $(am__ss_local_SOURCES_DIST) \ + $(am__ss_redir_SOURCES_DIST) $(ss_server_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -223,14 +230,8 @@ AM_CFLAGS = -g -O2 -Wall -fno-strict-aliasing -I$(top_builddir)/libev \ -I$(top_builddir)/libasyncns AM_LDFLAGS = -static SS_COMMON_LIBS = $(top_builddir)/libev/libev.la $(INET_NTOP_LIB) -ss_local_SOURCES = utils.c \ - jconf.c \ - json.c \ - encrypt.c \ - udprelay.c \ - cache.c \ - local.c - +ss_local_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c cache.c \ + local.c $(am__append_2) ss_server_SOURCES = utils.c \ jconf.c \ json.c \ @@ -355,6 +356,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-local.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-udprelay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-win32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-encrypt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-jconf.Po@am__quote@ @@ -483,6 +485,20 @@ ss_local-local.obj: local.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-local.obj `if test -f 'local.c'; then $(CYGPATH_W) 'local.c'; else $(CYGPATH_W) '$(srcdir)/local.c'; fi` +ss_local-win32.o: win32.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -MT ss_local-win32.o -MD -MP -MF $(DEPDIR)/ss_local-win32.Tpo -c -o ss_local-win32.o `test -f 'win32.c' || echo '$(srcdir)/'`win32.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_local-win32.Tpo $(DEPDIR)/ss_local-win32.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='win32.c' object='ss_local-win32.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-win32.o `test -f 'win32.c' || echo '$(srcdir)/'`win32.c + +ss_local-win32.obj: win32.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -MT ss_local-win32.obj -MD -MP -MF $(DEPDIR)/ss_local-win32.Tpo -c -o ss_local-win32.obj `if test -f 'win32.c'; then $(CYGPATH_W) 'win32.c'; else $(CYGPATH_W) '$(srcdir)/win32.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_local-win32.Tpo $(DEPDIR)/ss_local-win32.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='win32.c' object='ss_local-win32.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-win32.obj `if test -f 'win32.c'; then $(CYGPATH_W) 'win32.c'; else $(CYGPATH_W) '$(srcdir)/win32.c'; fi` + ss_server-utils.o: utils.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-utils.o -MD -MP -MF $(DEPDIR)/ss_server-utils.Tpo -c -o ss_server-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_server-utils.Tpo $(DEPDIR)/ss_server-utils.Po diff --git a/src/encrypt.h b/src/encrypt.h index 6db7eaa8..65d62206 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -3,7 +3,20 @@ #include "config.h" +#ifndef __MINGW32__ #include +#else + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#endif + #include #include #include diff --git a/src/jconf.c b/src/jconf.c index 85f9d159..dbf27ce0 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -17,7 +17,11 @@ static char *to_string(const json_value *value) } else if (value->type == json_integer) { +#ifdef __MINGW32__ + return strdup(ss_itoa(value->u.integer)); +#else return strdup(itoa(value->u.integer)); +#endif } else if (value->type == json_null) { diff --git a/src/local.c b/src/local.c index d9b46f97..867cc17d 100644 --- a/src/local.c +++ b/src/local.c @@ -1,18 +1,21 @@ #include #include -#include -#include #include #include -#include -#include -#include -#include #include #include #include #include +#ifndef __MINGW32__ +#include +#include +#include +#include +#include +#include +#endif + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -23,6 +26,10 @@ #define SET_INTERFACE #endif +#ifdef __MINGW32__ +#include "win32.h" +#endif + #include "utils.h" #include "local.h" #include "socks5.h" @@ -42,6 +49,7 @@ int verbose = 0; int udprelay = 0; +#ifndef __MINGW32__ static int setnonblocking(int fd) { int flags; @@ -49,6 +57,7 @@ static int setnonblocking(int fd) flags = 0; return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif #ifdef SET_INTERFACE int setinterface(int socket_fd, const char* interface_name) @@ -213,13 +222,13 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { struct socks5_request *request = (struct socks5_request *)remote->buf; - struct sockaddr_in s_addr; - memset(&s_addr, 0, sizeof(s_addr)); + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); if (udprelay && request->cmd == 3) { - socklen_t addr_len = sizeof(s_addr); - getsockname(server->fd, (struct sockaddr *)&s_addr, + socklen_t addr_len = sizeof(sock_addr); + getsockname(server->fd, (struct sockaddr *)&sock_addr, &addr_len); if (verbose) { @@ -338,11 +347,11 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) response.atyp = 1; memcpy(server->buf, &response, sizeof(struct socks5_response)); - memcpy(server->buf + sizeof(struct socks5_response), &s_addr.sin_addr, sizeof(s_addr.sin_addr)); - memcpy(server->buf + sizeof(struct socks5_response) + sizeof(s_addr.sin_addr), - &s_addr.sin_port, sizeof(s_addr.sin_port)); + memcpy(server->buf + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); + memcpy(server->buf + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), + &sock_addr.sin_port, sizeof(sock_addr.sin_port)); - int reply_size = sizeof(struct socks5_response) + sizeof(s_addr.sin_addr) + sizeof(s_addr.sin_port); + int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); int s = send(server->fd, server->buf, reply_size, 0); if (s < reply_size) { @@ -884,12 +893,16 @@ int main (int argc, char **argv) demonize(pid_path); } +#ifdef __MINGW32__ + winsock_init(); +#else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); +#endif // Setup keys - LOGD("initialize cihpers... %s", method); + LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket @@ -937,6 +950,11 @@ int main (int argc, char **argv) } ev_run (loop, 0); + +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + return 0; } diff --git a/src/udprelay.c b/src/udprelay.c index 282f9ace..65b3928a 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -1,19 +1,22 @@ #include #include -#include -#include #include #include -#include -#include -#include -#include #include #include #include #include #include +#ifndef __MINGW32__ +#include +#include +#include +#include +#include +#include +#endif + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -24,6 +27,10 @@ #define SET_INTERFACE #endif +#ifdef __MINGW32__ +#include "win32.h" +#endif + #include #include "utils.h" @@ -51,6 +58,7 @@ static char *iface; static int remote_conn = 0; static int server_conn = 0; +#ifndef __MINGW32__ static int setnonblocking(int fd) { int flags; @@ -58,6 +66,7 @@ static int setnonblocking(int fd) flags = 0; return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +#endif #ifdef SET_INTERFACE static int setinterface(int socket_fd, const char* interface_name) @@ -740,11 +749,11 @@ int udprelay_init(const char *server_host, const char *server_port, #ifdef UDPRELAY_REMOTE asyncns_t *asyncns, #endif - int method, const char *interface) + int method, const char *interface_name) { - iface = interface; + iface = interface_name; // Inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; diff --git a/src/udprelay.h b/src/udprelay.h index fdb79f9e..1de178c1 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -79,6 +79,6 @@ int udprelay(const char *server_host, const char *server_port, #ifdef UDPRELAY_REMOTE asyncns_t *asyncns, #endif - int method, const char *interface); + int method, const char *interface_name); #endif // _UDPRELAY_H diff --git a/src/utils.c b/src/utils.c index c686d121..a575d90f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,9 +1,7 @@ -#include #include #include #include #include -#include #include #include @@ -16,14 +14,20 @@ #define INT_DIGITS 19 /* enough for 64 bit integer */ +#ifndef __MINGW32__ void ERROR(const char *s) { char *msg = strerror(errno); LOGE("%s: %s", s, msg); } +#endif +#ifdef __MINGW32__ +char *ss_itoa(int i) +#else char *itoa(int i) +#endif { /* Room for INT_DIGITS digits, - and '\0' */ static char buf[INT_DIGITS + 2]; @@ -103,7 +107,7 @@ void usage() void demonize(const char* path) { - +#ifndef __MINGW32__ /* Our process ID and Session ID */ pid_t pid, sid; @@ -150,5 +154,6 @@ void demonize(const char* path) close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); +#endif } diff --git a/src/utils.h b/src/utils.h index 1b5560af..c49baa84 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,6 +1,9 @@ #ifndef _UTILS_H #define _UTILS_H +#include +#include + #ifdef ANDROID #include @@ -12,6 +15,27 @@ #define STR(x) #x #define TOSTR(x) STR(x) + +#ifdef _WIN32 + +#define TIME_FORMAT "%Y-%m-%d %H:%M:%S" + +#define LOGD(format, ...) do {\ + time_t now = time(NULL);\ + char timestr[20];\ + strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ + fprintf(stderr, " %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(stderr, " %s ERROR: " format "\n", timestr, ##__VA_ARGS__);}\ +while(0) + +#else + #define TIME_FORMAT "%F %T" #define LOGD(format, ...) do {\ @@ -28,13 +52,30 @@ while(0) fprintf(stderr, "\e[01;35m %s ERROR: \e[0m" format "\n", timestr, ##__VA_ARGS__);}\ while(0) +#endif +/* _WIN32 */ + #endif -void FATAL(const char *msg); +#ifdef __MINGW32__ + +#ifdef ERROR +#undef ERROR +#endif +#define ERROR(s) ss_error(s) + +char *ss_itoa(int i); + +#else + void ERROR(const char *s); +char *itoa(int i); + +#endif + +void FATAL(const char *msg); void usage(void); void demonize(const char* path); -char *itoa(int i); char *ss_strndup(const char *s, size_t n); #endif // _UTILS_H diff --git a/src/win32.c b/src/win32.c new file mode 100644 index 00000000..539a5033 --- /dev/null +++ b/src/win32.c @@ -0,0 +1,75 @@ +#include "win32.h" + +#ifdef setsockopt +#undef setsockopt +#endif + +void winsock_init(void) +{ + WORD wVersionRequested; + WSADATA wsaData; + int ret; + wVersionRequested = MAKEWORD(1, 1); + ret = WSAStartup(wVersionRequested, &wsaData); + if (ret != 0) { + FATAL("Could not initialize winsock"); + } + if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { + WSACleanup(); + FATAL("Could not find a usable version of winsock"); + } +} + +void winsock_cleanup(void) +{ + WSACleanup(); +} + +void ss_error(const char *s) +{ + LPVOID *msg = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &msg, 0, NULL); + if (msg != NULL) { + LOGE("%s: %s", s, msg); + LocalFree(msg); + } +} + +int setnonblocking(int fd) +{ + u_long iMode = 0; + int iResult; + iResult = ioctlsocket(fd, FIONBIO, &iMode); + if (iResult != NO_ERROR) { + LOGE("ioctlsocket failed with error: %ld\n", iResult); + } + return iResult; +} + +size_t strnlen(const char *s, size_t maxlen) +{ + const char *end = memchr(s, 0, maxlen); + return end ? (size_t) (end - s) : maxlen; +} + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ + struct sockaddr_storage ss; + unsigned long s = size; + ZeroMemory(&ss, sizeof(ss)); + ss.ss_family = af; + switch (af) { + case AF_INET: + ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; + break; + case AF_INET6: + ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; + break; + default: + return NULL; + } + return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ? dst : NULL; +} diff --git a/src/win32.h b/src/win32.h new file mode 100644 index 00000000..cd0edc10 --- /dev/null +++ b/src/win32.h @@ -0,0 +1,33 @@ +#ifndef _WIN32_H +#define _WIN32_H + +#define _WIN32_WINNT 0x0501 + +#include +#include +#include "utils.h" + +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif + +#ifdef errno +#undef errno +#endif + +#ifdef ERROR +#undef ERROR +#endif + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define errno WSAGetLastError() +#define close(fd) closesocket(fd) +#define ERROR(s) ss_error(s) +#define setsockopt(a, b, c, d, e) setsockopt(a, b, c, (char *) (d), e) + +void winsock_init(void); +void winsock_cleanup(void); +void ss_error(const char *s); +size_t strnlen(const char *s, size_t maxlen); + +#endif \ No newline at end of file