├── .gitmodules ├── src ├── uvw │ ├── config.h │ ├── stream.cpp │ ├── async.cpp │ ├── work.cpp │ ├── idle.cpp │ ├── check.cpp │ ├── prepare.cpp │ ├── emitter.cpp │ ├── lib.cpp │ ├── signal.cpp │ ├── timer.cpp │ ├── fs_poll.cpp │ ├── check.h │ ├── fs_event.cpp │ ├── prepare.h │ ├── poll.cpp │ ├── async.h │ ├── work.h │ ├── idle.h │ ├── lib.h │ ├── pipe.cpp │ ├── resource.hpp │ ├── tty.cpp │ ├── signal.h │ ├── request.hpp │ ├── fs_poll.h │ ├── timer.h │ ├── process.cpp │ ├── tcp.cpp │ ├── underlying_type.hpp │ ├── loop.cpp │ ├── poll.h │ ├── fs_event.h │ ├── tty.h │ ├── pipe.h │ ├── thread.cpp │ └── dns.cpp ├── CipherEnv.cpp ├── TCPRelay.hpp ├── CipherEnv.hpp ├── qt_ui_log.h ├── NetUtils.hpp ├── LogHelper.h ├── ObfsClass.hpp ├── qt_ui_log.cpp ├── obfs │ ├── base64.h │ ├── crc32.h │ ├── http_simple.h │ ├── tls1.2_ticket.h │ ├── obfsutil.h │ ├── auth.h │ ├── obfs.h │ ├── auth_chain.h │ ├── obfsutil.c │ ├── crc32.c │ └── base64.c ├── ObfsClass.cpp ├── ssr_log_utils.cpp ├── uvw_single.hpp ├── UDPConnectionContext.hpp ├── sockaddr_universal.h ├── UDPConnectionContext.cpp ├── shadowsocksr.h ├── ConnectionContext.hpp ├── SSRThread.hpp ├── ssrutils.c ├── sockaddr_universal.c ├── NetUtils.cpp ├── Buffer.hpp ├── cache.h ├── UDPRelay.hpp ├── SSRThread.cpp ├── win │ └── getopt.h ├── ssrutils.h ├── ConnectionContext.cpp ├── CMakeLists.txt ├── ssr_local.cpp └── encrypt.h ├── .gitignore ├── COPYING ├── config.h.cmake ├── cmake ├── dist.cmake ├── CheckPrototypeExists.cmake ├── CheckSTDC.cmake ├── configure.cmake ├── CheckDIRSymbolExists.cmake └── FindLibUV.cmake ├── test ├── CMakeLists.txt └── src │ ├── TestDualStack.cpp │ ├── TestBuffer.cpp │ └── TestNetUtils.cpp ├── README.md ├── CMakeLists.txt ├── .clang-format └── .github └── workflows └── build-shadowsocksr-uvw.yml /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libsodium"] 2 | path = libsodium 3 | url = https://github.com/jedisct1/libsodium.git 4 | [submodule "libuv"] 5 | path = libuv 6 | url = https://github.com/libuv/libuv.git 7 | -------------------------------------------------------------------------------- /src/uvw/config.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_CONFIG_H 2 | #define UVW_CONFIG_H 3 | 4 | 5 | #ifndef UVW_AS_LIB 6 | #define UVW_INLINE inline 7 | #else 8 | #define UVW_INLINE 9 | #endif 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/CipherEnv.cpp: -------------------------------------------------------------------------------- 1 | #include "CipherEnv.hpp" 2 | 3 | CipherEnv::CipherEnv(const char* passwd, const char* method) 4 | { 5 | memset(&cipher, 0, sizeof(cipher_env_t)); 6 | enc_init(&cipher, passwd, method); 7 | } 8 | 9 | CipherEnv::~CipherEnv() 10 | { 11 | enc_release(&cipher); 12 | } 13 | -------------------------------------------------------------------------------- /src/TCPRelay.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shadowsocksr.h" 3 | #include 4 | 5 | class TCPRelay 6 | { 7 | public: 8 | virtual ~TCPRelay()= default; 9 | virtual void stop() = 0; 10 | virtual int loopMain(profile_t&) = 0; 11 | static std::shared_ptr create(); 12 | }; -------------------------------------------------------------------------------- /src/CipherEnv.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CIPHERENV_HPP 2 | #define CIPHERENV_HPP 3 | #include "encrypt.h" 4 | 5 | #include 6 | 7 | class CipherEnv 8 | { 9 | public: 10 | cipher_env_t cipher {}; 11 | CipherEnv(const char* passwd, const char* method); 12 | ~CipherEnv(); 13 | }; 14 | 15 | #endif // CIPHERENV_HPP 16 | -------------------------------------------------------------------------------- /src/qt_ui_log.h: -------------------------------------------------------------------------------- 1 | #ifndef QT_UI_LOG_H 2 | #define QT_UI_LOG_H 3 | #ifdef __cplusplus 4 | extern "C" 5 | { 6 | #include 7 | #else 8 | #include 9 | #endif 10 | void qt_ui_log(const char* msg); 11 | void send_traffic_stat(uint64_t, uint64_t); 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | #endif // QT_UI_LOG_H 16 | -------------------------------------------------------------------------------- /src/NetUtils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #if defined(_WIN32) 3 | #include 4 | #else 5 | #include 6 | #endif 7 | #include 8 | 9 | namespace uvw 10 | { 11 | class Loop; 12 | } 13 | 14 | int ssr_get_sock_addr(std::shared_ptr loop, const char* host, int port, struct sockaddr_storage* storage, int ipv6first); 15 | -------------------------------------------------------------------------------- /src/LogHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGHELPER_H 2 | #define LOGHELPER_H 3 | #include "ssrutils.h" 4 | struct LogHelper 5 | { 6 | const char* p_; 7 | LogHelper(const char* p) 8 | : p_(p) 9 | { 10 | LOGI("enter %s", p); 11 | } 12 | ~LogHelper() 13 | { 14 | LOGI("leave %s", p_); 15 | } 16 | }; 17 | 18 | #endif // LOGHELPER_H 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | build/* 13 | 14 | # JB 15 | /.idea/ 16 | *.iml 17 | /cmake-build-debug 18 | 19 | # gtags 20 | GPATH 21 | GRTAGS 22 | GTAGS 23 | 24 | #vscode 25 | /.vscode/ -------------------------------------------------------------------------------- /src/uvw/stream.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "stream.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE DataEvent::DataEvent(std::unique_ptr buf, std::size_t len) noexcept 12 | : data{std::move(buf)}, length{len} 13 | {} 14 | 15 | 16 | UVW_INLINE void details::ShutdownReq::shutdown(uv_stream_t *handle) { 17 | invoke(&uv_shutdown, get(), handle, &defaultCallback); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/ObfsClass.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBFSCLASS_H 2 | #define OBFSCLASS_H 3 | #include "obfs/obfs.h" 4 | 5 | #include 6 | class ObfsClass 7 | { 8 | public: 9 | std::unique_ptr protocol_plugin; 10 | std::unique_ptr obfs_plugin; 11 | void* obfs_global = nullptr; 12 | void* protocol_global = nullptr; 13 | ObfsClass(const char* protocol, const char* obfs_name); 14 | ~ObfsClass(); 15 | }; 16 | #endif // OBFSCLASS_H 17 | -------------------------------------------------------------------------------- /src/qt_ui_log.cpp: -------------------------------------------------------------------------------- 1 | #include "qt_ui_log.h" 2 | 3 | #include "SSRThread.hpp" 4 | 5 | void send_traffic_stat(uint64_t tx, uint64_t rx) 6 | { 7 | auto ptr = dynamic_cast(QThread::currentThread()); 8 | if (!ptr) 9 | return; 10 | emit ptr->OnDataReady(tx, rx); 11 | } 12 | void qt_ui_log(const char* msg) 13 | { 14 | auto ptr = dynamic_cast(QThread::currentThread()); 15 | if (!ptr) 16 | return; 17 | emit ptr->onSSRThreadLog(QString { msg }); 18 | } 19 | -------------------------------------------------------------------------------- /src/uvw/async.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "async.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE void AsyncHandle::sendCallback(uv_async_t *handle) { 12 | AsyncHandle &async = *(static_cast(handle->data)); 13 | async.publish(AsyncEvent{}); 14 | } 15 | 16 | 17 | UVW_INLINE bool AsyncHandle::init() { 18 | return initialize(&uv_async_init, &sendCallback); 19 | } 20 | 21 | 22 | UVW_INLINE void AsyncHandle::send() { 23 | invoke(&uv_async_send, get()); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/obfs/base64.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBFS_BASE64_H 2 | #define _OBFS_BASE64_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | enum { 9 | BASE64_OK = 0, 10 | BASE64_INVALID 11 | }; 12 | 13 | #define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4) 14 | #define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3) 15 | 16 | int base64_encode(const unsigned char* in, unsigned int inlen, char* out); 17 | 18 | int base64_decode(const char* in, unsigned int inlen, unsigned char* out); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | #endif // _OBFS_BASE64_H 24 | -------------------------------------------------------------------------------- /src/uvw/work.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "work.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE WorkReq::WorkReq(ConstructorAccess ca, std::shared_ptr ref, InternalTask t) 14 | : Request{ca, std::move(ref)}, task{t} 15 | {} 16 | 17 | 18 | UVW_INLINE void WorkReq::workCallback(uv_work_t *req) { 19 | static_cast(req->data)->task(); 20 | } 21 | 22 | 23 | UVW_INLINE void WorkReq::queue() { 24 | invoke(&uv_queue_work, parent(), get(), &workCallback, &defaultCallback); 25 | } 26 | 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/obfs/crc32.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBFS_CRC32_H 2 | #define _OBFS_CRC32_H 3 | 4 | #include "obfs.h" 5 | #ifdef __cplusplus 6 | extern "C" 7 | { 8 | #endif 9 | void init_crc32_table(void); 10 | 11 | uint32_t crc32_ssr(unsigned char* buffer, unsigned int size); 12 | 13 | void fillcrc32to(unsigned char* buffer, unsigned int size, unsigned char* outbuffer); 14 | 15 | void fillcrc32(unsigned char* buffer, unsigned int size); 16 | 17 | void filladler32(unsigned char* buffer, unsigned int size); 18 | 19 | int checkadler32(unsigned char* buffer, unsigned int size); 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | #endif // _OBFS_CRC32_H 24 | -------------------------------------------------------------------------------- /src/uvw/idle.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "idle.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE void IdleHandle::startCallback(uv_idle_t *handle) { 12 | IdleHandle &idle = *(static_cast(handle->data)); 13 | idle.publish(IdleEvent{}); 14 | } 15 | 16 | 17 | UVW_INLINE bool IdleHandle::init() { 18 | return initialize(&uv_idle_init); 19 | } 20 | 21 | 22 | UVW_INLINE void IdleHandle::start() { 23 | invoke(&uv_idle_start, get(), &startCallback); 24 | } 25 | 26 | 27 | UVW_INLINE void IdleHandle::stop() { 28 | invoke(&uv_idle_stop, get()); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This program is free software: you can redistribute it and/or modify 2 | it under the terms of the GNU General Public License as published by 3 | the Free Software Foundation, either version 3 of the License, or 4 | (at your option) any later version. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | -------------------------------------------------------------------------------- /config.h.cmake: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #cmakedefine HAVE_INTTYPES_H 1 5 | 6 | /* Define to necessary symbol if this constant uses a non-standard name on 7 | your system. */ 8 | #cmakedefine PTHREAD_CREATE_JOINABLE @PTHREAD_CREATE_JOINABLE@ 9 | 10 | /* Use Apple CommonCrypto library */ 11 | #cmakedefine USE_CRYPTO_APPLECC 1 12 | 13 | /* Use mbed TLS library */ 14 | #cmakedefine USE_CRYPTO_MBEDTLS 1 15 | 16 | /* Use OpenSSL library */ 17 | #cmakedefine USE_CRYPTO_OPENSSL 1 18 | 19 | /* Use PolarSSL library */ 20 | #cmakedefine USE_CRYPTO_POLARSSL 1 21 | 22 | -------------------------------------------------------------------------------- /src/uvw/check.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "check.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE void CheckHandle::startCallback(uv_check_t *handle) { 12 | CheckHandle &check = *(static_cast(handle->data)); 13 | check.publish(CheckEvent{}); 14 | } 15 | 16 | 17 | UVW_INLINE bool CheckHandle::init() { 18 | return initialize(&uv_check_init); 19 | } 20 | 21 | 22 | UVW_INLINE void CheckHandle::start() { 23 | invoke(&uv_check_start, get(), &startCallback); 24 | } 25 | 26 | 27 | UVW_INLINE void CheckHandle::stop() { 28 | invoke(&uv_check_stop, get()); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/ObfsClass.cpp: -------------------------------------------------------------------------------- 1 | #include "ObfsClass.hpp" 2 | 3 | ObfsClass::ObfsClass(const char* protocol, const char* obfs_name) 4 | : protocol_plugin(new_obfs_class(protocol), free) 5 | , obfs_plugin(new_obfs_class(obfs_name), free) 6 | { 7 | if (protocol_plugin) 8 | protocol_global = protocol_plugin->init_data(); 9 | if (obfs_plugin) 10 | obfs_global = obfs_plugin->init_data(); 11 | } 12 | 13 | ObfsClass::~ObfsClass() 14 | { 15 | if (protocol_global != nullptr) { 16 | free(protocol_global); 17 | protocol_global = nullptr; 18 | } 19 | if (obfs_global != nullptr) { 20 | free(obfs_global); 21 | obfs_global = nullptr; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/uvw/prepare.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "prepare.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE void PrepareHandle::startCallback(uv_prepare_t *handle) { 12 | PrepareHandle &prepare = *(static_cast(handle->data)); 13 | prepare.publish(PrepareEvent{}); 14 | } 15 | 16 | 17 | UVW_INLINE bool PrepareHandle::init() { 18 | return initialize(&uv_prepare_init); 19 | } 20 | 21 | 22 | UVW_INLINE void PrepareHandle::start() { 23 | invoke(&uv_prepare_start, get(), &startCallback); 24 | } 25 | 26 | 27 | UVW_INLINE void PrepareHandle::stop() { 28 | invoke(&uv_prepare_stop, get()); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/uvw/emitter.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "emitter.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE int ErrorEvent::translate(int sys) noexcept { 12 | return uv_translate_sys_error(sys); 13 | } 14 | 15 | 16 | 17 | UVW_INLINE const char * ErrorEvent::what() const noexcept { 18 | return uv_strerror(ec); 19 | } 20 | 21 | 22 | UVW_INLINE const char * ErrorEvent::name() const noexcept { 23 | return uv_err_name(ec); 24 | } 25 | 26 | 27 | UVW_INLINE int ErrorEvent::code() const noexcept { 28 | return ec; 29 | } 30 | 31 | 32 | UVW_INLINE ErrorEvent::operator bool() const noexcept { 33 | return ec < 0; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/ssr_log_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "ssrutils.h" 2 | #include 3 | #include 4 | 5 | #ifdef SSR_UVW_WITH_QT 6 | #include "qt_ui_log.h" 7 | #endif 8 | 9 | namespace 10 | { 11 | constexpr int SSR_LOG_BUFFER_SIZE = 1024; 12 | void _ssr_log_write(char* msg) 13 | { 14 | #ifdef SSR_UVW_WITH_QT 15 | qt_ui_log(msg); 16 | #else 17 | strcat(msg, "\n"); 18 | fprintf(stderr, "%s", msg); 19 | fflush(stderr); 20 | #endif 21 | } 22 | } 23 | 24 | void ssr_log_print(const char* fmt, ...) 25 | { 26 | va_list ap; 27 | char buf[SSR_LOG_BUFFER_SIZE]; 28 | va_start(ap, fmt); 29 | vsnprintf(buf, SSR_LOG_BUFFER_SIZE, fmt, ap); 30 | va_end(ap); 31 | return _ssr_log_write(buf); 32 | } 33 | -------------------------------------------------------------------------------- /src/uvw/lib.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "lib.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE SharedLib::SharedLib(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref, std::string filename) noexcept 14 | : UnderlyingType{ca, std::move(ref)} 15 | { 16 | opened = (0 == uv_dlopen(filename.data(), get())); 17 | } 18 | 19 | 20 | UVW_INLINE SharedLib::~SharedLib() noexcept { 21 | uv_dlclose(get()); 22 | } 23 | 24 | 25 | UVW_INLINE SharedLib::operator bool() const noexcept { 26 | return opened; 27 | } 28 | 29 | 30 | UVW_INLINE const char *SharedLib::error() const noexcept { 31 | return uv_dlerror(get()); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/uvw_single.hpp: -------------------------------------------------------------------------------- 1 | #include "uvw/async.h" 2 | #include "uvw/check.h" 3 | #include "uvw/config.h" 4 | #include "uvw/dns.h" 5 | #include "uvw/emitter.h" 6 | #include "uvw/fs.h" 7 | #include "uvw/fs_event.h" 8 | #include "uvw/fs_poll.h" 9 | #include "uvw/handle.hpp" 10 | #include "uvw/idle.h" 11 | #include "uvw/lib.h" 12 | #include "uvw/loop.h" 13 | #include "uvw/pipe.h" 14 | #include "uvw/poll.h" 15 | #include "uvw/prepare.h" 16 | #include "uvw/process.h" 17 | #include "uvw/request.hpp" 18 | #include "uvw/resource.hpp" 19 | #include "uvw/signal.h" 20 | #include "uvw/tcp.h" 21 | #include "uvw/thread.h" 22 | #include "uvw/timer.h" 23 | #include "uvw/tty.h" 24 | #include "uvw/udp.h" 25 | #include "uvw/underlying_type.hpp" 26 | #include "uvw/util.h" 27 | #include "uvw/work.h" 28 | -------------------------------------------------------------------------------- /src/obfs/http_simple.h: -------------------------------------------------------------------------------- 1 | /* 2 | * http_simple.h - Define shadowsocksR server's buffers and callbacks 3 | * 4 | * Copyright (C) 2015 - 2016, Break Wa11 5 | */ 6 | 7 | #ifndef _OBFS_HTTP_SIMPLE_H 8 | #define _OBFS_HTTP_SIMPLE_H 9 | 10 | #include "obfs.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | obfs* http_simple_new_obfs(); 17 | void http_simple_dispose(obfs* self); 18 | 19 | int http_simple_client_encode(obfs* self, char** pencryptdata, int datalength, size_t* capacity); 20 | int http_simple_client_decode(obfs* self, char** pencryptdata, int datalength, size_t* capacity, int* needsendback); 21 | 22 | int http_post_client_encode(obfs* self, char** pencryptdata, int datalength, size_t* capacity); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | #endif // _OBFS_HTTP_SIMPLE_H 28 | -------------------------------------------------------------------------------- /src/obfs/tls1.2_ticket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tls1.2_ticket.h - Define shadowsocksR server's buffers and callbacks 3 | * 4 | * Copyright (C) 2015 - 2017, Break Wa11 5 | */ 6 | 7 | #ifndef _OBFS_TLS1_2_TICKET_H 8 | #define _OBFS_TLS1_2_TICKET_H 9 | 10 | #include "obfs.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | void* tls12_ticket_auth_init_data(); 17 | obfs* tls12_ticket_auth_new_obfs(); 18 | void tls12_ticket_auth_dispose(obfs* self); 19 | 20 | int tls12_ticket_auth_client_encode(obfs* self, char** pencryptdata, int datalength, size_t* capacity); 21 | int tls12_ticket_auth_client_decode(obfs* self, char** pencryptdata, int datalength, size_t* capacity, int* needsendback); 22 | 23 | int tls12_ticket_auth_get_overhead(obfs* self); 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | #endif // _OBFS_TLS1_2_TICKET_H 28 | -------------------------------------------------------------------------------- /src/UDPConnectionContext.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHADOWSOCKSR_UVW_UDPCONNECTIONCONTEXT_HPP 2 | #define SHADOWSOCKSR_UVW_UDPCONNECTIONCONTEXT_HPP 3 | #include 4 | 5 | #include "uvw/loop.h" 6 | #include "uvw/timer.h" 7 | #include "uvw/udp.h" 8 | 9 | class Buffer; 10 | 11 | class UDPConnectionContext 12 | { 13 | public: 14 | std::shared_ptr timeoutTimer; 15 | uvw::Addr srcAddr; 16 | std::unique_ptr remoteBuf; 17 | std::shared_ptr remote; 18 | UDPConnectionContext() = default; 19 | UDPConnectionContext(uvw::Addr addr, std::shared_ptr remoteSocket); 20 | void initTimer(std::shared_ptr& loop, std::function panic, uvw::TimerHandle::Time timeout); 21 | void resetTimeoutTimer(); 22 | ~UDPConnectionContext(); 23 | }; 24 | 25 | #endif //SHADOWSOCKSR_UVW_UDPCONNECTIONCONTEXT_HPP 26 | -------------------------------------------------------------------------------- /cmake/dist.cmake: -------------------------------------------------------------------------------- 1 | # LuaDist CMake utility library. 2 | # Provides sane project defaults and macros common to LuaDist CMake builds. 3 | # 4 | # Copyright (C) 2007-2012 LuaDist. 5 | # by David Manura, Peter Drahoš 6 | # Redistribution and use of this file is allowed according to the terms of the MIT license. 7 | # For details see the COPYRIGHT file distributed with LuaDist. 8 | # Please note that the package source code is licensed under its own license. 9 | 10 | 11 | # Tweaks and other defaults 12 | # Setting CMAKE to use loose block and search for find modules in source directory 13 | set ( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true ) 14 | set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} ) 15 | 16 | # In MSVC, prevent warnings that can occur when using standard libraries. 17 | if ( MSVC ) 18 | add_definitions ( -D_CRT_SECURE_NO_WARNINGS ) 19 | endif () 20 | 21 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(WIN32) 2 | set(WINSOCK2 ws2_32) 3 | elseif(NOT APPLE) 4 | find_library(LIBRT rt) 5 | endif() 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | function(ADD_SSR_UVW_TEST TEST_NAME TEST_SOURCE) 10 | add_executable(${TEST_NAME} ${TEST_SOURCE}) 11 | target_include_directories(${TEST_NAME} 12 | PRIVATE 13 | $ 14 | ) 15 | target_link_libraries( 16 | ${TEST_NAME} 17 | PRIVATE 18 | shadowsocksr::uvw 19 | ${LIBRT} 20 | ${WINSOCK2} 21 | ) 22 | 23 | add_test(NAME SSR_UVW_${TEST_NAME} COMMAND $) 24 | endfunction() 25 | 26 | ADD_SSR_UVW_TEST(TESTBUFFER src/TestBuffer.cpp) 27 | ADD_SSR_UVW_TEST(TESTDUALSTACK src/TestDualStack.cpp) 28 | ADD_SSR_UVW_TEST(TESTNETUTILS src/TestNetUtils.cpp) 29 | 30 | -------------------------------------------------------------------------------- /src/sockaddr_universal.h: -------------------------------------------------------------------------------- 1 | #if !defined(__sockaddr_universal_h__) 2 | #define __sockaddr_universal_h__ 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | #if defined(_WIN32) 9 | #include 10 | #else 11 | #include 12 | #endif // defined(_WIN32) 13 | 14 | #include 15 | #include 16 | 17 | enum SOCKS5_ADDRTYPE { 18 | SOCKS5_ADDRTYPE_INVALID = 0x00, 19 | SOCKS5_ADDRTYPE_IPV4 = 0x01, 20 | SOCKS5_ADDRTYPE_DOMAINNAME = 0x03, 21 | SOCKS5_ADDRTYPE_IPV6 = 0x04, 22 | }; 23 | 24 | struct socks5_address 25 | { 26 | enum SOCKS5_ADDRTYPE addr_type; 27 | union { 28 | struct in_addr ipv4; 29 | struct in6_addr ipv6; 30 | char domainname[0x0100]; 31 | } addr; 32 | uint16_t port; 33 | }; 34 | 35 | bool socks5_address_parse(const uint8_t* data, size_t len, struct socks5_address* addr); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | #endif // !defined(__sockaddr_universal_h__) 41 | -------------------------------------------------------------------------------- /src/uvw/signal.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "signal.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE SignalEvent::SignalEvent(int sig) noexcept 12 | : signum{sig} 13 | {} 14 | 15 | 16 | UVW_INLINE void SignalHandle::startCallback(uv_signal_t *handle, int signum) { 17 | SignalHandle &signal = *(static_cast(handle->data)); 18 | signal.publish(SignalEvent{signum}); 19 | } 20 | 21 | 22 | UVW_INLINE bool SignalHandle::init() { 23 | return initialize(&uv_signal_init); 24 | } 25 | 26 | 27 | UVW_INLINE void SignalHandle::start(int signum) { 28 | invoke(&uv_signal_start, get(), &startCallback, signum); 29 | } 30 | 31 | 32 | UVW_INLINE void SignalHandle::oneShot(int signum) { 33 | invoke(&uv_signal_start_oneshot, get(), &startCallback, signum); 34 | } 35 | 36 | 37 | UVW_INLINE void SignalHandle::stop() { 38 | invoke(&uv_signal_stop, get()); 39 | } 40 | 41 | 42 | UVW_INLINE int SignalHandle::signal() const noexcept { 43 | return get()->signum; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/obfs/obfsutil.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBFS_OBFSUTIL_H 2 | #define _OBFS_OBFSUTIL_H 3 | #include 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | #ifndef _MSC_VER 9 | #define VLA(TYPE, SIZE, NAME) TYPE NAME[SIZE] 10 | #define VLA_FREE(NAME) 11 | #else 12 | #define VLA(TYPE, SIZE, NAME) TYPE* NAME = (TYPE*)malloc(sizeof(TYPE) * SIZE) 13 | #define VLA_FREE(NAME) free(NAME) 14 | #endif 15 | int get_head_size(char* plaindata, int size, int def_size); 16 | 17 | void init_shift128plus(void); 18 | 19 | uint64_t xorshift128plus(void); 20 | 21 | int ss_md5_hmac(char* auth, char* msg, int msg_len, uint8_t* iv, int enc_iv_len, uint8_t* enc_key, int enc_key_len); 22 | 23 | int ss_sha1_hmac(char* auth, char* msg, int msg_len, uint8_t* iv, int enc_iv_len, uint8_t* enc_key, int enc_key_len); 24 | 25 | int data_size_list_compare(const void* a, const void* b); 26 | 27 | int find_pos(int arr[], int length, int key); 28 | 29 | void memintcopy_lt(void* mem, uint32_t val); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | #endif // _OBFS_OBFSUTIL_H 35 | -------------------------------------------------------------------------------- /src/uvw/timer.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "timer.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE void TimerHandle::startCallback(uv_timer_t *handle) { 12 | TimerHandle &timer = *(static_cast(handle->data)); 13 | timer.publish(TimerEvent{}); 14 | } 15 | 16 | 17 | UVW_INLINE bool TimerHandle::init() { 18 | return initialize(&uv_timer_init); 19 | } 20 | 21 | 22 | UVW_INLINE void TimerHandle::start(TimerHandle::Time timeout, TimerHandle::Time repeat) { 23 | invoke(&uv_timer_start, get(), &startCallback, timeout.count(), repeat.count()); 24 | } 25 | 26 | 27 | UVW_INLINE void TimerHandle::stop() { 28 | invoke(&uv_timer_stop, get()); 29 | } 30 | 31 | 32 | UVW_INLINE void TimerHandle::again() { 33 | invoke(&uv_timer_again, get()); 34 | } 35 | 36 | 37 | UVW_INLINE void TimerHandle::repeat(TimerHandle::Time repeat) { 38 | uv_timer_set_repeat(get(), repeat.count()); 39 | } 40 | 41 | 42 | UVW_INLINE TimerHandle::Time TimerHandle::repeat() { 43 | return Time{uv_timer_get_repeat(get())}; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/UDPConnectionContext.cpp: -------------------------------------------------------------------------------- 1 | #include "UDPConnectionContext.hpp" 2 | 3 | #include "Buffer.hpp" 4 | 5 | UDPConnectionContext::~UDPConnectionContext() 6 | { 7 | if( timeoutTimer) 8 | timeoutTimer->close(); 9 | if (remote) { 10 | remote->clear(); 11 | remote->close(); 12 | } 13 | } 14 | 15 | UDPConnectionContext::UDPConnectionContext(uvw::Addr addr, std::shared_ptr remoteSocket) 16 | : srcAddr(std::move(addr)) 17 | , remoteBuf(std::make_unique()) 18 | , remote(std::move(remoteSocket)) 19 | { 20 | } 21 | void UDPConnectionContext::initTimer(std::shared_ptr& loop, std::function panic, uvw::TimerHandle::Time timeout) 22 | { 23 | timeoutTimer = loop->resource(); 24 | timeoutTimer->on([addr = srcAddr, panic = std::move(panic)](auto&, uvw::TimerHandle& h) { 25 | h.stop(); 26 | h.close(); 27 | //before we panic, we must stop and close silently. 28 | panic(); //destroy this UDPConnectionContext instance. 29 | }); 30 | timeoutTimer->start(timeout, timeout); 31 | } 32 | void UDPConnectionContext::resetTimeoutTimer() 33 | { 34 | if (timeoutTimer) 35 | timeoutTimer->again(); 36 | } 37 | -------------------------------------------------------------------------------- /src/uvw/fs_poll.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "fs_poll.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE FsPollEvent::FsPollEvent(Stat previous, Stat current) noexcept 14 | : prev{std::move(previous)}, curr{std::move(current)} 15 | {} 16 | 17 | 18 | UVW_INLINE void FsPollHandle::startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) { 19 | FsPollHandle &fsPoll = *(static_cast(handle->data)); 20 | 21 | if(status) { 22 | fsPoll.publish(ErrorEvent{status}); 23 | } else { 24 | fsPoll.publish(FsPollEvent{*prev, *curr}); 25 | } 26 | } 27 | 28 | 29 | UVW_INLINE bool FsPollHandle::init() { 30 | return initialize(&uv_fs_poll_init); 31 | } 32 | 33 | 34 | UVW_INLINE void FsPollHandle::start(std::string file, FsPollHandle::Time interval) { 35 | invoke(&uv_fs_poll_start, get(), &startCallback, file.data(), interval.count()); 36 | } 37 | 38 | 39 | UVW_INLINE void FsPollHandle::stop() { 40 | invoke(&uv_fs_poll_stop, get()); 41 | } 42 | 43 | 44 | UVW_INLINE std::string FsPollHandle::path() noexcept { 45 | return details::tryRead(&uv_fs_poll_getpath, get()); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/uvw/check.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_CHECK_INCLUDE_H 2 | #define UVW_CHECK_INCLUDE_H 3 | 4 | 5 | #include 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | /** 14 | * @brief CheckEvent event. 15 | * 16 | * It will be emitted by CheckHandle according with its functionalities. 17 | */ 18 | struct CheckEvent {}; 19 | 20 | 21 | /** 22 | * @brief The CheckHandle handle. 23 | * 24 | * Check handles will emit a CheckEvent event once per loop iteration, right 25 | * after polling for I/O. 26 | * 27 | * To create a `CheckHandle` through a `Loop`, no arguments are required. 28 | */ 29 | class CheckHandle final: public Handle { 30 | static void startCallback(uv_check_t *handle); 31 | 32 | public: 33 | using Handle::Handle; 34 | 35 | /** 36 | * @brief Initializes the handle. 37 | * @return True in case of success, false otherwise. 38 | */ 39 | bool init(); 40 | 41 | /** 42 | * @brief Starts the handle. 43 | * 44 | * A CheckEvent event will be emitted once per loop iteration, right after 45 | * polling for I/O. 46 | */ 47 | void start(); 48 | 49 | /** 50 | * @brief Stops the handle. 51 | */ 52 | void stop(); 53 | }; 54 | 55 | 56 | } 57 | 58 | 59 | #ifndef UVW_AS_LIB 60 | #include "check.cpp" 61 | #endif 62 | 63 | #endif // UVW_CHECK_INCLUDE_H 64 | -------------------------------------------------------------------------------- /src/shadowsocksr.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADOWSOCKSR_UVW_SHADOWSOCKSR_H 2 | #define SHADOWSOCKSR_UVW_SHADOWSOCKSR_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | typedef struct 10 | { 11 | /* Required */ 12 | const char* remote_host; // hostname or ip of remote server 13 | const char* local_addr; // local ip to bind 14 | const char* method; // encryption method 15 | const char* password; // password of remote server 16 | int remote_port; // port number of remote server 17 | int local_port; // port number of local server 18 | int timeout; // connection timeout 19 | const char* obfs; // ssr 20 | const char* obfs_param; // ssr 21 | const char* protocol; // ssr 22 | const char* protocol_param; // ssr 23 | /* Optional, set NULL if not valid */ 24 | const char* acl; // file path to acl 25 | int fast_open; // enable tcp fast open 26 | int mode; // enable udp relay 27 | // mode 0 is TCP_ONLY 28 | // mode 1 is TCP_AND_UDP 29 | int mtu; // MTU of interface 30 | int verbose; // verbose mode 31 | int ipv6first; 32 | } profile_t; 33 | 34 | int start_ssr_uv_local_server(profile_t profile); 35 | int stop_ssr_uv_local_server(); 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif // SHADOWSOCKSR_UVW_SHADOWSOCKSR_H 41 | -------------------------------------------------------------------------------- /cmake/CheckPrototypeExists.cmake: -------------------------------------------------------------------------------- 1 | # - Check if the prototype for a function exists. 2 | # CHECK_PROTOTYPE_EXISTS (FUNCTION HEADER VARIABLE) 3 | # 4 | # FUNCTION - the name of the function you are looking for 5 | # HEADER - the header(s) where the prototype should be declared 6 | # VARIABLE - variable to store the result 7 | # 8 | # The following variables may be set before calling this macro to 9 | # modify the way the check is run: 10 | # 11 | # CMAKE_REQUIRED_FLAGS = string of compile command line flags 12 | # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) 13 | # CMAKE_REQUIRED_INCLUDES = list of include directories 14 | 15 | # Copyright (c) 2006, Alexander Neundorf, 16 | # 17 | # Redistribution and use is allowed according to the terms of the BSD license. 18 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 19 | 20 | 21 | INCLUDE(CheckCSourceCompiles) 22 | 23 | MACRO (CHECK_PROTOTYPE_EXISTS _SYMBOL _HEADER _RESULT) 24 | SET(_INCLUDE_FILES) 25 | FOREACH (it ${_HEADER}) 26 | SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") 27 | ENDFOREACH (it) 28 | 29 | SET(_CHECK_PROTO_EXISTS_SOURCE_CODE " 30 | ${_INCLUDE_FILES} 31 | int main() 32 | { 33 | #ifndef ${_SYMBOL} 34 | int i = sizeof(&${_SYMBOL}); 35 | #endif 36 | return 0; 37 | } 38 | ") 39 | 40 | CHECK_C_SOURCE_COMPILES("${_CHECK_PROTO_EXISTS_SOURCE_CODE}" ${_RESULT}) 41 | ENDMACRO (CHECK_PROTOTYPE_EXISTS _SYMBOL _HEADER _RESULT) 42 | -------------------------------------------------------------------------------- /src/uvw/fs_event.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "fs_event.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE FsEventEvent::FsEventEvent(const char * pathname, Flags events) 14 | : filename{pathname}, flags{std::move(events)} 15 | {} 16 | 17 | 18 | UVW_INLINE void FsEventHandle::startCallback(uv_fs_event_t *handle, const char *filename, int events, int status) { 19 | FsEventHandle &fsEvent = *(static_cast(handle->data)); 20 | 21 | if(status) { 22 | fsEvent.publish(ErrorEvent{status}); 23 | } else { 24 | fsEvent.publish(FsEventEvent{filename, static_cast>(events)}); 25 | } 26 | } 27 | 28 | 29 | UVW_INLINE bool FsEventHandle::init() { 30 | return initialize(&uv_fs_event_init); 31 | } 32 | 33 | 34 | UVW_INLINE void FsEventHandle::start(std::string path, Flags flags) { 35 | invoke(&uv_fs_event_start, get(), &startCallback, path.data(), flags); 36 | } 37 | 38 | 39 | UVW_INLINE void FsEventHandle::start(std::string path, FsEventHandle::Event flag) { 40 | start(std::move(path), Flags{flag}); 41 | } 42 | 43 | 44 | UVW_INLINE void FsEventHandle::stop() { 45 | invoke(&uv_fs_event_stop, get()); 46 | } 47 | 48 | 49 | UVW_INLINE std::string FsEventHandle::path() noexcept { 50 | return details::tryRead(&uv_fs_event_getpath, get()); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /cmake/CheckSTDC.cmake: -------------------------------------------------------------------------------- 1 | message(STATUS "Checking whether system has ANSI C header files") 2 | include(CheckPrototypeExists) 3 | include(CheckIncludeFiles) 4 | 5 | check_include_files("dlfcn.h;stdint.h;stddef.h;inttypes.h;stdlib.h;strings.h;string.h;float.h" StandardHeadersExist) 6 | if(StandardHeadersExist) 7 | check_prototype_exists(memchr string.h memchrExists) 8 | if(memchrExists) 9 | check_prototype_exists(free stdlib.h freeExists) 10 | if(freeExists) 11 | message(STATUS "ANSI C header files - found") 12 | set(STDC_HEADERS 1 CACHE INTERNAL "System has ANSI C header files") 13 | set(HAVE_STRINGS_H 1) 14 | set(HAVE_STRING_H 1) 15 | set(HAVE_FLOAT_H 1) 16 | set(HAVE_STDLIB_H 1) 17 | set(HAVE_STDDEF_H 1) 18 | set(HAVE_STDINT_H 1) 19 | set(HAVE_INTTYPES_H 1) 20 | set(HAVE_DLFCN_H 1) 21 | endif(freeExists) 22 | endif(memchrExists) 23 | endif(StandardHeadersExist) 24 | 25 | if(NOT STDC_HEADERS) 26 | message(STATUS "ANSI C header files - not found") 27 | set(STDC_HEADERS 0 CACHE INTERNAL "System has ANSI C header files") 28 | endif(NOT STDC_HEADERS) 29 | 30 | check_include_files(unistd.h HAVE_UNISTD_H) 31 | 32 | include(CheckDIRSymbolExists) 33 | check_dirsymbol_exists("sys/stat.h;sys/types.h;dirent.h" HAVE_DIRENT_H) 34 | if (HAVE_DIRENT_H) 35 | set(HAVE_SYS_STAT_H 1) 36 | set(HAVE_SYS_TYPES_H 1) 37 | endif (HAVE_DIRENT_H) 38 | -------------------------------------------------------------------------------- /src/uvw/prepare.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_PREPARE_INCLUDE_H 2 | #define UVW_PREPARE_INCLUDE_H 3 | 4 | 5 | #include 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | /** 14 | * @brief PrepareEvent event. 15 | * 16 | * It will be emitted by PrepareHandle according with its functionalities. 17 | */ 18 | struct PrepareEvent {}; 19 | 20 | 21 | /** 22 | * @brief The PrepareHandle handle. 23 | * 24 | * Prepare handles will emit a PrepareEvent event once per loop iteration, right 25 | * before polling for I/O. 26 | * 27 | * To create a `PrepareHandle` through a `Loop`, no arguments are required. 28 | */ 29 | class PrepareHandle final: public Handle { 30 | static void startCallback(uv_prepare_t *handle); 31 | 32 | public: 33 | using Handle::Handle; 34 | 35 | /** 36 | * @brief Initializes the handle. 37 | * @return True in case of success, false otherwise. 38 | */ 39 | bool init(); 40 | 41 | /** 42 | * @brief Starts the handle. 43 | * 44 | * A PrepareEvent event will be emitted once per loop iteration, right 45 | * before polling for I/O. 46 | * 47 | * The handle will start emitting PrepareEvent when needed. 48 | */ 49 | void start(); 50 | 51 | /** 52 | * @brief Stops the handle. 53 | */ 54 | void stop(); 55 | }; 56 | 57 | 58 | } 59 | 60 | 61 | #ifndef UVW_AS_LIB 62 | #include "prepare.cpp" 63 | #endif 64 | 65 | #endif // UVW_PREPARE_INCLUDE_H 66 | -------------------------------------------------------------------------------- /src/uvw/poll.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "poll.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE PollEvent::PollEvent(Flags events) noexcept 14 | : flags{std::move(events)} 15 | {} 16 | 17 | 18 | UVW_INLINE PollHandle::PollHandle(ConstructorAccess ca, std::shared_ptr ref, int desc) 19 | : Handle{ca, std::move(ref)}, tag{FD}, fd{desc} 20 | {} 21 | 22 | 23 | UVW_INLINE PollHandle::PollHandle(ConstructorAccess ca, std::shared_ptr ref, OSSocketHandle sock) 24 | : Handle{ca, std::move(ref)}, tag{SOCKET}, socket{sock} 25 | {} 26 | 27 | 28 | UVW_INLINE void PollHandle::startCallback(uv_poll_t *handle, int status, int events) { 29 | PollHandle &poll = *(static_cast(handle->data)); 30 | 31 | if(status) { 32 | poll.publish(ErrorEvent{status}); 33 | } else { 34 | poll.publish(PollEvent{static_cast>(events)}); 35 | } 36 | } 37 | 38 | 39 | UVW_INLINE bool PollHandle::init() { 40 | return (tag == SOCKET) ? initialize(&uv_poll_init_socket, socket) : initialize(&uv_poll_init, fd); 41 | } 42 | 43 | 44 | UVW_INLINE void PollHandle::start(Flags flags) { 45 | invoke(&uv_poll_start, get(), flags, &startCallback); 46 | } 47 | 48 | 49 | UVW_INLINE void PollHandle::start(PollHandle::Event event) { 50 | start(Flags{event}); 51 | } 52 | 53 | 54 | UVW_INLINE void PollHandle::stop() { 55 | invoke(&uv_poll_stop, get()); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/ConnectionContext.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONNECTIONCONTEXT_H 2 | #define CONNECTIONCONTEXT_H 3 | #include 4 | extern "C" 5 | { 6 | #include "obfs/obfs.h" 7 | #include "shadowsocksr.h" 8 | } 9 | #include "CipherEnv.hpp" 10 | namespace uvw 11 | { 12 | class TCPHandle; 13 | } 14 | #include "Buffer.hpp" 15 | 16 | #include 17 | class ConnectionContext 18 | { 19 | private: 20 | ObfsClass* obfsClassPtr = nullptr; 21 | CipherEnv* cipherEnvPtr = nullptr; 22 | 23 | public: 24 | using enc_ctx_release_t = std::function; 25 | std::unique_ptr localBuf; 26 | std::unique_ptr remoteBuf; 27 | std::unique_ptr protocolPtr; 28 | std::unique_ptr obfsPtr; 29 | std::unique_ptr e_ctx; 30 | std::unique_ptr d_ctx; 31 | std::shared_ptr client; 32 | std::shared_ptr remote; 33 | 34 | ConnectionContext(std::shared_ptr tcpHandle, ObfsClass* obfsClassPtr, CipherEnv* cipherEnvPtr); 35 | 36 | ConnectionContext(); 37 | 38 | ConnectionContext(ConnectionContext&&) noexcept; 39 | 40 | ConnectionContext& operator=(ConnectionContext&&) noexcept; 41 | 42 | void setRemoteTcpHandle(std::shared_ptr tcp); 43 | 44 | server_info_t construct_obfs(CipherEnv& cipherEnv, ObfsClass& obfsClass, const profile_t& profile, int server_info_head_len); 45 | 46 | ~ConnectionContext(); 47 | }; 48 | 49 | #endif // CONNECTIONCONTEXT_H 50 | -------------------------------------------------------------------------------- /src/uvw/async.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_ASYNC_INCLUDE_H 2 | #define UVW_ASYNC_INCLUDE_H 3 | 4 | 5 | #include 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | /** 14 | * @brief AsyncEvent event. 15 | * 16 | * It will be emitted by AsyncHandle according with its functionalities. 17 | */ 18 | struct AsyncEvent {}; 19 | 20 | 21 | /** 22 | * @brief The AsyncHandle handle. 23 | * 24 | * Async handles allow the user to _wakeup_ the event loop and get an event 25 | * emitted from another thread. 26 | * 27 | * To create an `AsyncHandle` through a `Loop`, no arguments are required. 28 | */ 29 | class AsyncHandle final: public Handle { 30 | static void sendCallback(uv_async_t *handle); 31 | 32 | public: 33 | using Handle::Handle; 34 | 35 | /** 36 | * @brief Initializes the handle. 37 | * 38 | * Unlike other handle initialization functions, it immediately starts the 39 | * handle. 40 | * 41 | * @return True in case of success, false otherwise. 42 | */ 43 | bool init(); 44 | 45 | /** 46 | * @brief Wakeups the event loop and emits the AsyncEvent event. 47 | * 48 | * It’s safe to call this function from any thread.
49 | * An AsyncEvent event will be emitted on the loop thread. 50 | * 51 | * See the official 52 | * [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send) 53 | * for further details. 54 | */ 55 | void send(); 56 | }; 57 | 58 | 59 | } 60 | 61 | 62 | #ifndef UVW_AS_LIB 63 | #include "async.cpp" 64 | #endif 65 | 66 | #endif // UVW_ASYNC_INCLUDE_H 67 | -------------------------------------------------------------------------------- /cmake/configure.cmake: -------------------------------------------------------------------------------- 1 | # Build args 2 | if(USE_SYSTEM_LIBUV) 3 | if(NOT WIN32) 4 | find_package(LibUV REQUIRED) 5 | else() 6 | find_package(unofficial-libuv CONFIG REQUIRED) 7 | set(${LibUV_LIBRARIES} unofficial::libuv::libuv) 8 | endif() 9 | endif() 10 | 11 | if (${WITH_CRYPTO_LIBRARY} STREQUAL "openssl") 12 | find_package(OpenSSL REQUIRED) 13 | if(USE_SYSTEM_SODIUM) 14 | if(NOT WIN32) 15 | find_package(Sodium REQUIRED) 16 | else() 17 | find_package(unofficial-sodium CONFIG REQUIRED) 18 | set(${sodium_LIBRARIES} unofficial-sodium::sodium) 19 | endif() 20 | endif() 21 | set(USE_CRYPTO_OPENSSL 1) 22 | if(NOT WIN32) 23 | set(LIBCRYPTO 24 | ${OPENSSL_CRYPTO_LIBRARY}) 25 | else() 26 | set(LIBCRYPTO OpenSSL::SSL OpenSSL::Crypto) 27 | endif() 28 | message("found open ssl") 29 | include_directories(${OPENSSL_INCLUDE_DIR}) 30 | 31 | list ( APPEND CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) 32 | 33 | elseif(${with_crypto_library} STREQUAL "polarssl") 34 | find_package(polarssl REQUIRED) 35 | set(USE_CRYPTO_POLARSSL 1) 36 | elseif(${with_crypto_library} STREQUAL "mbedtls") 37 | find_package(mbedtls REQUIRED) 38 | set(USE_CRYPTO_MBEDTLS 1) 39 | endif() 40 | 41 | 42 | 43 | # Platform checks 44 | include ( CheckFunctionExists ) 45 | include ( CheckIncludeFiles ) 46 | include ( CheckSymbolExists ) 47 | include ( CheckCSourceCompiles ) 48 | include ( CheckTypeSize ) 49 | include ( CheckSTDC ) 50 | 51 | check_include_files ( inttypes.h HAVE_INTTYPES_H ) 52 | 53 | ADD_DEFINITIONS(-DHAVE_CONFIG_H) 54 | -------------------------------------------------------------------------------- /src/uvw/work.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_WORK_INCLUDE_H 2 | #define UVW_WORK_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "request.hpp" 9 | #include "loop.h" 10 | 11 | 12 | namespace uvw { 13 | 14 | 15 | /** 16 | * @brief WorkEvent event. 17 | * 18 | * It will be emitted by WorkReq according with its functionalities. 19 | */ 20 | struct WorkEvent {}; 21 | 22 | 23 | /** 24 | * @brief The WorkReq request. 25 | * 26 | * It runs user code using a thread from the threadpool and gets notified in the 27 | * loop thread by means of an event. 28 | * 29 | * To create a `WorkReq` through a `Loop`, arguments follow: 30 | * 31 | * * A valid instance of a `Task`, that is of type `std::function`. 32 | * 33 | * See the official 34 | * [documentation](http://docs.libuv.org/en/v1.x/threadpool.html) 35 | * for further details. 36 | */ 37 | class WorkReq final: public Request { 38 | using InternalTask = std::function; 39 | 40 | static void workCallback(uv_work_t *req); 41 | 42 | public: 43 | using Task = InternalTask; 44 | 45 | explicit WorkReq(ConstructorAccess ca, std::shared_ptr ref, InternalTask t); 46 | 47 | /** 48 | * @brief Runs the given task in a separate thread. 49 | * 50 | * A WorkEvent event will be emitted on the loop thread when the task is 51 | * finished.
52 | * This request can be cancelled with `cancel()`. 53 | */ 54 | void queue(); 55 | 56 | private: 57 | Task task{}; 58 | }; 59 | 60 | 61 | } 62 | 63 | 64 | #ifndef UVW_AS_LIB 65 | #include "work.cpp" 66 | #endif 67 | 68 | #endif // UVW_WORK_INCLUDE_H 69 | -------------------------------------------------------------------------------- /src/uvw/idle.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_IDLE_INCLUDE_H 2 | #define UVW_IDLE_INCLUDE_H 3 | 4 | 5 | #include 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | /** 14 | * @brief IdleEvent event. 15 | * 16 | * It will be emitted by IdleHandle according with its functionalities. 17 | */ 18 | struct IdleEvent {}; 19 | 20 | 21 | /** 22 | * @brief The IdleHandle handle. 23 | * 24 | * Idle handles will emit a IdleEvent event once per loop iteration, right 25 | * before the PrepareHandle handles. 26 | * 27 | * The notable difference with prepare handles is that when there are active 28 | * idle handles, the loop will perform a zero timeout poll instead of blocking 29 | * for I/O. 30 | * 31 | * @note 32 | * Despite the name, idle handles will emit events on every loop iteration, not 33 | * when the loop is actually _idle_. 34 | * 35 | * To create an `IdleHandle` through a `Loop`, no arguments are required. 36 | */ 37 | class IdleHandle final: public Handle { 38 | static void startCallback(uv_idle_t *handle); 39 | 40 | public: 41 | using Handle::Handle; 42 | 43 | /** 44 | * @brief Initializes the handle. 45 | * @return True in case of success, false otherwise. 46 | */ 47 | bool init(); 48 | 49 | /** 50 | * @brief Starts the handle. 51 | * 52 | * A IdleEvent event will be emitted once per loop iteration, right before 53 | * polling the PrepareHandle handles. 54 | */ 55 | void start(); 56 | 57 | /** 58 | * @brief Stops the handle. 59 | */ 60 | void stop(); 61 | }; 62 | 63 | 64 | } 65 | 66 | 67 | #ifndef UVW_AS_LIB 68 | #include "idle.cpp" 69 | #endif 70 | 71 | #endif // UVW_IDLE_INCLUDE_H 72 | -------------------------------------------------------------------------------- /src/SSRThread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SSRTHREAD_HPP 2 | #define SSRTHREAD_HPP 3 | #include 4 | class TCPRelay; 5 | class SSRThread : public QThread 6 | { 7 | Q_OBJECT 8 | public: 9 | enum class SSR_WORK_MODE { TCP_ONLY = 0, 10 | TCP_AND_UDP = 1 }; 11 | explicit SSRThread() = default; 12 | explicit SSRThread(int localPort, 13 | int remotePort, 14 | std::string local_addr, 15 | std::string remote_host, 16 | std::string method, 17 | std::string password, 18 | std::string obfs, 19 | std::string obfs_param, 20 | std::string protocol, 21 | std::string protocol_param); 22 | explicit SSRThread(int localPort, 23 | int remotePort, 24 | int timeout, 25 | int mtu, 26 | SSR_WORK_MODE mode, 27 | std::string local_addr, 28 | std::string remote_host, 29 | std::string method, 30 | std::string password, 31 | std::string obfs, 32 | std::string obfs_param, 33 | std::string protocol, 34 | std::string protocol_param, 35 | int ipv6first = 0, 36 | int verbose = 0); 37 | ~SSRThread() override; 38 | signals: 39 | void OnDataReady(quint64 dataUp, quint64 dataDown); 40 | void onSSRThreadLog(QString); 41 | 42 | protected: 43 | void run() override; 44 | 45 | public slots: 46 | void stop(); 47 | 48 | private: 49 | int localPort = 0; 50 | int remotePort = 0; 51 | int timeout = 60000; //ms 52 | int mtu = 0; 53 | int mode = 0; 54 | std::string local_addr; 55 | std::string remote_host; 56 | std::string method; 57 | std::string password; 58 | std::string obfs; 59 | std::string obfs_param; 60 | std::string protocol; 61 | std::string protocol_param; 62 | int ipv6first = 0; 63 | int verbose = 0; 64 | std::shared_ptr tcpRelay; 65 | }; 66 | #endif // SSRTHREAD_HPP 67 | -------------------------------------------------------------------------------- /src/uvw/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_LIB_INCLUDE_H 2 | #define UVW_LIB_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "loop.h" 10 | #include "underlying_type.hpp" 11 | 12 | 13 | namespace uvw { 14 | 15 | 16 | /** 17 | * @brief The SharedLib class. 18 | * 19 | * `uvw` provides cross platform utilities for loading shared libraries and 20 | * retrieving symbols from them, by means of the API offered by `libuv`. 21 | */ 22 | class SharedLib final: public UnderlyingType { 23 | public: 24 | explicit SharedLib(ConstructorAccess ca, std::shared_ptr ref, std::string filename) noexcept; 25 | 26 | ~SharedLib() noexcept; 27 | 28 | /** 29 | * @brief Checks if the library has been correctly opened. 30 | * @return True if the library is opened, false otherwise. 31 | */ 32 | explicit operator bool() const noexcept; 33 | 34 | /** 35 | * @brief Retrieves a data pointer from a dynamic library. 36 | * 37 | * `F` shall be a valid function type (as an example, `void(int)`).
38 | * It is legal for a symbol to map to `nullptr`. 39 | * 40 | * @param name The symbol to be retrieved. 41 | * @return A valid function pointer in case of success, `nullptr` otherwise. 42 | */ 43 | template 44 | F * sym(std::string name) { 45 | static_assert(std::is_function_v); 46 | F *func; 47 | auto err = uv_dlsym(get(), name.data(), reinterpret_cast(&func)); 48 | if(err) { func = nullptr; } 49 | return func; 50 | } 51 | 52 | /** 53 | * @brief Returns the last error message, if any. 54 | * @return The last error message, if any. 55 | */ 56 | const char * error() const noexcept; 57 | 58 | private: 59 | bool opened; 60 | }; 61 | 62 | 63 | } 64 | 65 | 66 | #ifndef UVW_AS_LIB 67 | #include "lib.cpp" 68 | #endif 69 | 70 | #endif // UVW_LIB_INCLUDE_H 71 | -------------------------------------------------------------------------------- /src/uvw/pipe.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "pipe.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE PipeHandle::PipeHandle(ConstructorAccess ca, std::shared_ptr ref, bool pass) 14 | : StreamHandle{ca, std::move(ref)}, ipc{pass} 15 | {} 16 | 17 | 18 | UVW_INLINE bool PipeHandle::init() { 19 | return initialize(&uv_pipe_init, ipc); 20 | } 21 | 22 | 23 | UVW_INLINE void PipeHandle::open(FileHandle file) { 24 | invoke(&uv_pipe_open, get(), file); 25 | } 26 | 27 | 28 | UVW_INLINE void PipeHandle::bind(std::string name) { 29 | invoke(&uv_pipe_bind, get(), name.data()); 30 | } 31 | 32 | 33 | UVW_INLINE void PipeHandle::connect(std::string name) { 34 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 35 | ptr->publish(event); 36 | }; 37 | 38 | auto connect = loop().resource(); 39 | connect->once(listener); 40 | connect->once(listener); 41 | connect->connect(&uv_pipe_connect, get(), name.data()); 42 | } 43 | 44 | 45 | UVW_INLINE std::string PipeHandle::sock() const noexcept { 46 | return details::tryRead(&uv_pipe_getsockname, get()); 47 | } 48 | 49 | 50 | UVW_INLINE std::string PipeHandle::peer() const noexcept { 51 | return details::tryRead(&uv_pipe_getpeername, get()); 52 | } 53 | 54 | 55 | UVW_INLINE void PipeHandle::pending(int count) noexcept { 56 | uv_pipe_pending_instances(get(), count); 57 | } 58 | 59 | 60 | UVW_INLINE int PipeHandle::pending() noexcept { 61 | return uv_pipe_pending_count(get()); 62 | } 63 | 64 | 65 | UVW_INLINE HandleType PipeHandle::receive() noexcept { 66 | HandleCategory category = uv_pipe_pending_type(get()); 67 | return Utilities::guessHandle(category); 68 | } 69 | 70 | 71 | UVW_INLINE bool PipeHandle::chmod(Flags flags) noexcept { 72 | return (0 == uv_pipe_chmod(get(), flags)); 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/ssrutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.c - Misc utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the shadowsocks-libev. 7 | * 8 | * shadowsocks-libev is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * shadowsocks-libev is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with shadowsocks-libev; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include "ssrutils.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | int use_tty = 0; 34 | 35 | struct tm* ssr_safe_localtime(time_t* t, struct tm* tp) 36 | { 37 | #ifdef _WIN32 38 | //windows localtime is thread safe 39 | //https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-localtime32-localtime64?view=vs-2019 40 | return localtime(t); 41 | #else 42 | return localtime_r(t, tp); 43 | #endif 44 | } 45 | 46 | void FATAL(const char* msg) 47 | { 48 | LOGE("%s", msg); 49 | exit(-1); 50 | } 51 | 52 | void* ss_malloc(size_t size) 53 | { 54 | void* tmp = malloc(size); 55 | if (tmp == NULL) 56 | exit(EXIT_FAILURE); 57 | return tmp; 58 | } 59 | 60 | void* ss_realloc(void* ptr, size_t new_size) 61 | { 62 | void* new = realloc(ptr, new_size); 63 | if (new == NULL) { 64 | free(ptr); 65 | ptr = NULL; 66 | exit(EXIT_FAILURE); 67 | } 68 | return new; 69 | } 70 | -------------------------------------------------------------------------------- /src/obfs/auth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * auth.h - Define shadowsocksR server's buffers and callbacks 3 | * 4 | * Copyright (C) 2015 - 2016, Break Wa11 5 | */ 6 | 7 | #ifndef _OBFS_AUTH_H 8 | #define _OBFS_AUTH_H 9 | 10 | #include "obfs.h" 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | void* auth_simple_init_data(); 16 | obfs* auth_simple_new_obfs(); 17 | obfs* auth_aes128_md5_new_obfs(); 18 | obfs* auth_aes128_sha1_new_obfs(); 19 | void auth_simple_dispose(obfs* self); 20 | 21 | // int auth_simple_client_pre_encrypt(obfs *self, char **pplaindata, int 22 | // datalength, size_t* capacity); int auth_simple_client_post_decrypt(obfs *self, 23 | // char **pplaindata, int datalength, size_t* capacity); 24 | 25 | int auth_sha1_client_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 26 | int auth_sha1_client_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 27 | 28 | int auth_sha1_v2_client_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 29 | int auth_sha1_v2_client_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 30 | 31 | int auth_sha1_v4_client_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 32 | int auth_sha1_v4_client_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 33 | 34 | int auth_aes128_sha1_client_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 35 | int auth_aes128_sha1_client_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 36 | 37 | int auth_aes128_sha1_client_udp_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 38 | int auth_aes128_sha1_client_udp_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 39 | 40 | int auth_aes128_sha1_get_overhead(obfs* self); 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | #endif // _OBFS_AUTH_H 45 | -------------------------------------------------------------------------------- /src/uvw/resource.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_RESOURCE_INCLUDE_H 2 | #define UVW_RESOURCE_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include "emitter.h" 8 | #include "underlying_type.hpp" 9 | 10 | 11 | namespace uvw { 12 | 13 | 14 | /** 15 | * @brief Common class for almost all the resources available in `uvw`. 16 | * 17 | * This is the base class for handles and requests. 18 | */ 19 | template 20 | class Resource: public UnderlyingType, public Emitter, public std::enable_shared_from_this { 21 | protected: 22 | using ConstructorAccess = typename UnderlyingType::ConstructorAccess; 23 | 24 | auto parent() const noexcept { 25 | return this->loop().loop.get(); 26 | } 27 | 28 | void leak() noexcept { 29 | sPtr = this->shared_from_this(); 30 | } 31 | 32 | void reset() noexcept { 33 | sPtr.reset(); 34 | } 35 | 36 | bool self() const noexcept { 37 | return static_cast(sPtr); 38 | } 39 | 40 | public: 41 | explicit Resource(ConstructorAccess ca, std::shared_ptr ref) 42 | : UnderlyingType{ca, std::move(ref)}, 43 | Emitter{}, 44 | std::enable_shared_from_this{} 45 | { 46 | this->get()->data = this; 47 | } 48 | 49 | /** 50 | * @brief Gets user-defined data. `uvw` won't use this field in any case. 51 | * @return User-defined data if any, an invalid pointer otherwise. 52 | */ 53 | template 54 | std::shared_ptr data() const { 55 | return std::static_pointer_cast(userData); 56 | } 57 | 58 | /** 59 | * @brief Sets arbitrary data. `uvw` won't use this field in any case. 60 | * @param uData User-defined arbitrary data. 61 | */ 62 | void data(std::shared_ptr uData) { 63 | userData = std::move(uData); 64 | } 65 | 66 | private: 67 | std::shared_ptr userData{nullptr}; 68 | std::shared_ptr sPtr{nullptr}; 69 | }; 70 | 71 | } 72 | 73 | #endif // UVW_RESOURCE_INCLUDE_H 74 | -------------------------------------------------------------------------------- /src/uvw/tty.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "tty.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include "config.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | UVW_INLINE details::ResetModeMemo::~ResetModeMemo() { 14 | uv_tty_reset_mode(); 15 | } 16 | 17 | 18 | UVW_INLINE TTYHandle::TTYHandle(ConstructorAccess ca, std::shared_ptr ref, FileHandle desc, bool readable) 19 | : StreamHandle{ca, std::move(ref)}, 20 | memo{resetModeMemo()}, 21 | fd{desc}, 22 | rw{readable} 23 | {} 24 | 25 | 26 | UVW_INLINE std::shared_ptr TTYHandle::resetModeMemo() { 27 | static std::weak_ptr weak; 28 | auto shared = weak.lock(); 29 | if(!shared) { weak = shared = std::make_shared(); } 30 | return shared; 31 | }; 32 | 33 | 34 | UVW_INLINE bool TTYHandle::init() { 35 | return initialize(&uv_tty_init, fd, rw); 36 | } 37 | 38 | 39 | UVW_INLINE bool TTYHandle::mode(TTYHandle::Mode m) { 40 | return (0 == uv_tty_set_mode(get(), static_cast>(m))); 41 | } 42 | 43 | 44 | UVW_INLINE bool TTYHandle::reset() noexcept { 45 | return (0 == uv_tty_reset_mode()); 46 | } 47 | 48 | 49 | UVW_INLINE WinSize TTYHandle::getWinSize() { 50 | WinSize size; 51 | 52 | if(0 != uv_tty_get_winsize(get(), &size.width, &size.height)) { 53 | size.width = -1; 54 | size.height = -1; 55 | } 56 | 57 | return size; 58 | } 59 | 60 | 61 | UVW_INLINE void TTYHandle::vtermState(TTYHandle::VTermState s) const noexcept { 62 | switch(s) { 63 | case VTermState::SUPPORTED: 64 | uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_SUPPORTED); 65 | break; 66 | case VTermState::UNSUPPORTED: 67 | uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_UNSUPPORTED); 68 | break; 69 | } 70 | } 71 | 72 | 73 | UVW_INLINE TTYHandle::VTermState TTYHandle::vtermState() const noexcept { 74 | uv_tty_vtermstate_t state; 75 | uv_tty_get_vterm_state(&state); 76 | return VTermState{state}; 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/uvw/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_SIGNAL_INCLUDE_H 2 | #define UVW_SIGNAL_INCLUDE_H 3 | 4 | 5 | #include 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | 10 | namespace uvw { 11 | 12 | 13 | /** 14 | * @brief SignalEvent event. 15 | * 16 | * It will be emitted by SignalHandle according with its functionalities. 17 | */ 18 | struct SignalEvent { 19 | explicit SignalEvent(int sig) noexcept; 20 | 21 | int signum; /*!< The signal being monitored by this handle. */ 22 | }; 23 | 24 | 25 | /** 26 | * @brief The SignalHandle handle. 27 | * 28 | * Signal handles implement Unix style signal handling on a per-event loop 29 | * bases.
30 | * Reception of some signals is emulated on Windows. 31 | * 32 | * To create a `SignalHandle` through a `Loop`, no arguments are required. 33 | * 34 | * See the official 35 | * [documentation](http://docs.libuv.org/en/v1.x/signal.html) 36 | * for further details. 37 | */ 38 | class SignalHandle final: public Handle { 39 | static void startCallback(uv_signal_t *handle, int signum); 40 | 41 | public: 42 | using Handle::Handle; 43 | 44 | /** 45 | * @brief Initializes the handle. 46 | * @return True in case of success, false otherwise. 47 | */ 48 | bool init(); 49 | 50 | /** 51 | * @brief Starts the handle. 52 | * 53 | * The handle will start emitting SignalEvent when needed. 54 | * 55 | * @param signum The signal to be monitored. 56 | */ 57 | void start(int signum); 58 | 59 | /** 60 | * @brief Starts the handle. 61 | * 62 | * Same functionality as SignalHandle::start but the signal handler is reset 63 | * the moment the signal is received. 64 | * 65 | * @param signum 66 | */ 67 | void oneShot(int signum); 68 | 69 | /** 70 | * @brief Stops the handle. 71 | */ 72 | void stop(); 73 | 74 | /** 75 | * @brief Gets the signal being monitored. 76 | * @return The signal being monitored. 77 | */ 78 | int signal() const noexcept; 79 | }; 80 | 81 | 82 | } 83 | 84 | 85 | #ifndef UVW_AS_LIB 86 | #include "signal.cpp" 87 | #endif 88 | 89 | #endif // UVW_SIGNAL_INCLUDE_H 90 | -------------------------------------------------------------------------------- /src/uvw/request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_REQUEST_INCLUDE_H 2 | #define UVW_REQUEST_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "resource.hpp" 10 | 11 | 12 | namespace uvw { 13 | 14 | 15 | template 16 | class Request: public Resource { 17 | protected: 18 | static auto reserve(U *req) { 19 | auto ptr = static_cast(req->data)->shared_from_this(); 20 | ptr->reset(); 21 | return ptr; 22 | } 23 | 24 | template 25 | static void defaultCallback(U *req, int status) { 26 | auto ptr = reserve(req); 27 | if(status) { ptr->publish(ErrorEvent{status}); } 28 | else { ptr->publish(E{}); } 29 | } 30 | 31 | template 32 | auto invoke(F &&f, Args&&... args) { 33 | if constexpr(std::is_void_v>) { 34 | std::forward(f)(std::forward(args)...); 35 | this->leak(); 36 | } else { 37 | auto err = std::forward(f)(std::forward(args)...); 38 | if(err) { Emitter::publish(ErrorEvent{err}); } 39 | else { this->leak(); } 40 | } 41 | } 42 | 43 | public: 44 | using Resource::Resource; 45 | 46 | /** 47 | * @brief Cancels a pending request. 48 | * 49 | * This method fails if the request is executing or has finished 50 | * executing.
51 | * It can emit an ErrorEvent event in case of errors. 52 | * 53 | * See the official 54 | * [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel) 55 | * for further details. 56 | * 57 | * @return True in case of success, false otherwise. 58 | */ 59 | bool cancel() { 60 | return (0 == uv_cancel(this->template get())); 61 | } 62 | 63 | /** 64 | * @brief Returns the size of the underlying request type. 65 | * @return The size of the underlying request type. 66 | */ 67 | std::size_t size() const noexcept { 68 | return uv_req_size(this->template get()->type); 69 | } 70 | }; 71 | 72 | 73 | } 74 | 75 | #endif // UVW_REQUEST_INCLUDE_H 76 | -------------------------------------------------------------------------------- /src/uvw/fs_poll.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_FS_POLL_INCLUDE_H 2 | #define UVW_FS_POLL_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "handle.hpp" 9 | #include "util.h" 10 | #include "loop.h" 11 | 12 | 13 | namespace uvw { 14 | 15 | 16 | /** 17 | * @brief FsPollEvent event. 18 | * 19 | * It will be emitted by FsPollHandle according with its functionalities. 20 | */ 21 | struct FsPollEvent { 22 | explicit FsPollEvent(Stat previous, Stat current) noexcept; 23 | 24 | Stat prev; /*!< The old Stat struct. */ 25 | Stat curr; /*!< The new Stat struct. */ 26 | }; 27 | 28 | 29 | /** 30 | * @brief The FsPollHandle handle. 31 | * 32 | * It allows the user to monitor a given path for changes. Unlike FsEventHandle 33 | * handles, FsPollHandle handles use stat to detect when a file has changed so 34 | * they can work on file systems where FsEventHandle handles can’t. 35 | * 36 | * To create a `FsPollHandle` through a `Loop`, no arguments are required. 37 | */ 38 | class FsPollHandle final: public Handle { 39 | static void startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr); 40 | 41 | public: 42 | using Time = std::chrono::duration; 43 | 44 | using Handle::Handle; 45 | 46 | /** 47 | * @brief Initializes the handle. 48 | * @return True in case of success, false otherwise. 49 | */ 50 | bool init(); 51 | 52 | /** 53 | * @brief Starts the handle. 54 | * 55 | * The handle will start emitting FsPollEvent when needed. 56 | * 57 | * @param file The path to the file to be checked. 58 | * @param interval Milliseconds between successive checks. 59 | */ 60 | void start(std::string file, Time interval); 61 | 62 | /** 63 | * @brief Stops the handle. 64 | */ 65 | void stop(); 66 | 67 | /** 68 | * @brief Gets the path being monitored by the handle. 69 | * @return The path being monitored by the handle, an empty string in case 70 | * of errors. 71 | */ 72 | std::string path() noexcept; 73 | }; 74 | 75 | 76 | } 77 | 78 | 79 | #ifndef UVW_AS_LIB 80 | #include "fs_poll.cpp" 81 | #endif 82 | 83 | #endif // UVW_FS_POLL_INCLUDE_H 84 | -------------------------------------------------------------------------------- /src/sockaddr_universal.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #if !defined(_WIN32) 6 | #include 7 | #endif // !defined(_WIN32) 8 | 9 | #include "sockaddr_universal.h" 10 | 11 | // +----+-----+-------+------+----------+----------+ 12 | // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 13 | // +----+-----+-------+------+----------+----------+ 14 | // | 1 | 1 | X'00' | 1 | Variable | 2 | 15 | // +----+-----+-------+------+----------+----------+ 16 | // data start from atyp 17 | bool socks5_address_parse(const uint8_t* data, size_t len, struct socks5_address* addr) 18 | { 19 | size_t offset = 0; 20 | size_t addr_size = 0; 21 | uint8_t addr_type = 0; 22 | 23 | if (data == NULL || len == 0 || addr == NULL) { 24 | return false; 25 | } 26 | 27 | addr_type = data[offset++]; 28 | 29 | switch ((enum SOCKS5_ADDRTYPE)addr_type) { 30 | case SOCKS5_ADDRTYPE_IPV4: 31 | addr_size = sizeof(struct in_addr); 32 | if (len < sizeof(uint8_t) + addr_size + sizeof(uint16_t)) { 33 | return false; 34 | } 35 | addr->addr_type = SOCKS5_ADDRTYPE_IPV4; 36 | memcpy(&addr->addr.ipv4, data + offset, addr_size); 37 | break; 38 | case SOCKS5_ADDRTYPE_DOMAINNAME: 39 | addr_size = (size_t)data[offset++]; 40 | if (len < sizeof(uint8_t) + sizeof(uint8_t) + addr_size + sizeof(uint16_t)) { 41 | return false; 42 | } 43 | addr->addr_type = SOCKS5_ADDRTYPE_DOMAINNAME; 44 | memset(addr->addr.domainname, 0, sizeof(addr->addr.domainname)); 45 | memcpy(addr->addr.domainname, data + offset, addr_size); 46 | break; 47 | case SOCKS5_ADDRTYPE_IPV6: 48 | addr_size = sizeof(struct in6_addr); 49 | if (len < sizeof(uint8_t) + addr_size + sizeof(uint16_t)) { 50 | return false; 51 | } 52 | addr->addr_type = SOCKS5_ADDRTYPE_IPV6; 53 | memcpy(&addr->addr.ipv6, data + offset, addr_size); 54 | break; 55 | default: 56 | addr->addr_type = SOCKS5_ADDRTYPE_INVALID; 57 | return false; 58 | break; 59 | } 60 | offset += addr_size; 61 | 62 | addr->port = ntohs(*((uint16_t*)(data + offset))); 63 | 64 | offset += sizeof(uint16_t); 65 | 66 | return true; 67 | } 68 | -------------------------------------------------------------------------------- /src/NetUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "NetUtils.hpp" 2 | #include "ssrutils.h" 3 | #include "uvw/dns.h" 4 | #include "uvw/loop.h" 5 | #include 6 | 7 | int ssr_get_sock_addr(std::shared_ptr loop, const char* host, int port, struct sockaddr_storage* storage, int ipv6first) 8 | { 9 | if (uv_ip4_addr(host, port, reinterpret_cast(storage)) == 0) { 10 | return 0; 11 | } 12 | if (uv_ip6_addr(host, port, reinterpret_cast(storage)) == 0) { 13 | return 0; 14 | } 15 | //not an ip 16 | auto getAddrInfoReq = loop->resource(); 17 | char digitBuffer[20] = { 0 }; 18 | sprintf(digitBuffer, "%d", port); 19 | struct addrinfo hints; 20 | memset(&hints, 0, sizeof(struct addrinfo)); 21 | hints.ai_family = AF_UNSPEC; 22 | hints.ai_socktype = SOCK_STREAM; 23 | auto dns_res = getAddrInfoReq->addrInfoSync(host, digitBuffer, &hints); 24 | int prefer_af = ipv6first ? AF_INET6 : AF_INET; 25 | if (dns_res.first) { 26 | struct addrinfo* rp = nullptr; 27 | for (rp = dns_res.second.get(); rp != nullptr; rp = rp->ai_next) 28 | if (rp->ai_family == prefer_af) { 29 | if (rp->ai_family == AF_INET) 30 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); 31 | else if (rp->ai_family == AF_INET6) 32 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); 33 | break; 34 | } 35 | if (rp == nullptr) { 36 | //fallback: if we can't find prefered AF, then we choose alternative. 37 | for (rp = dns_res.second.get(); rp != nullptr; rp = rp->ai_next) { 38 | if (rp->ai_family == AF_INET) 39 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); 40 | else if (rp->ai_family == AF_INET6) 41 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); 42 | break; 43 | } 44 | } 45 | if (rp == nullptr) { 46 | LOGE("DNS not resolved %s:%d", host, port); 47 | return -1; // dns not resolved 48 | } 49 | return 0; 50 | } else { 51 | LOGE("DNS not resolved %s:%d", host, port); 52 | return -1; // dns not resolved 53 | } 54 | return -1; 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## shadowsocksr-uvw 2 | 3 | A minimal dependency shadowsocksr implementation. 4 | 5 | 6 | ## How to build 7 | If you want shadowsocksr-uvw to avoid using the system's own libuv and libsodium, the default compilation options will be helpful. The compilation options are as follows, which will link libuv and libsodium statically. 8 | ````bash 9 | git submodule update --init --recursive 10 | mkdir build 11 | cd build 12 | cmake .. -DSSR_UVW_WITH_QT=0 13 | make 14 | ```` 15 | By default, shadowsocksr-uvw will use the libuv and libsodium in the submodule for static linking. To avoid this, you can directly specify the compilation options as shown below. 16 | ````bash 17 | mkdir build 18 | cd build 19 | cmake .. -DSSR_UVW_WITH_QT=0 -DUSE_SYSTEM_SODIUM=ON -DUSE_SYSTEM_LIBUV=ON -DSTATIC_LINK_LIBUV=OFF -DSTATIC_LINK_SODIUM=OFF 20 | make 21 | ```` 22 | 23 | ## Encrypto method 24 | 25 | | | | | | | | 26 | | -----|-|-|-|-|-------------- | 27 | | none | rc4 | rc4-md5-6 | rc4-md5 |||| 28 | | aes-128-cfb | aes-192-cfb | aes-256-cfb |||| 29 | | aes-128-ctr | aes-192-ctr | aes-256-ctr |||| 30 | | camellia-128-cfb | camellia-192-cfb | camellia-256-cfb |||| 31 | | bf-cfb | cast5-cfb | des-cfb | idea-cfb | rc2-cfb | seed-cfb | 32 | | salsa20 | chacha20 | chacha20-ietf |||| 33 | 34 | ## Protocols 35 | 36 | | Protocols | 37 | | --------- | 38 | | origin | 39 | | auth_sha1| 40 | | auth_sha1_v2 | 41 | | auth_sha1_v4 | 42 | | auth_aes128_sha1 | 43 | | auth_aes128_md5 | 44 | | auth_chain_a | 45 | | auth_chain_b | 46 | | auth_chain_c | 47 | | auth_chain_d | 48 | | auth_chain_e | 49 | | auth_chain_f | 50 | 51 | ## obfuscators 52 | 53 | | obfuscators | 54 | | ----------- | 55 | | plain | 56 | | http_simple | 57 | | http_post | 58 | | tls1.2_ticket_auth | 59 | 60 | 61 | ## Licence 62 | 63 | shadowsocksr-uvw is under [GPLv3](LICENSE) licence. It's based on [uvw](https://github.com/skypjack/uvw) which is a header-only, event based, tiny and easy to use 64 | [`libuv`](https://github.com/libuv/libuv) wrapper in modern C++. 65 | 66 | ## Link dependencies 67 | 68 | | Name | License | 69 | | ---------------------- | -------------- | 70 | | [libuv](https://github.com/libuv/libuv) | MIT | 71 | | [libsodium](https://libsodium.org) | ISC | 72 | | [openssl](https://www.openssl.org/)| Apache| 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/Buffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SSRUVBUFFER_H 2 | #define SSRUVBUFFER_H 3 | #include 4 | extern "C" 5 | { 6 | #include "encrypt.h" 7 | } 8 | class CipherEnv; 9 | class ObfsClass; 10 | class ConnectionContext; 11 | class UDPRelay; 12 | namespace uvw 13 | { 14 | struct DataEvent; 15 | struct UDPDataEvent; 16 | } 17 | class Buffer 18 | { 19 | // +----+-----+-------+------+----------+----------+ 20 | // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 21 | // +----+-----+-------+------+----------+----------+ 22 | // | 1 | 1 | X'00' | 1 | Variable | 2 | 23 | // +----+-----+-------+------+----------+----------+ 24 | public: 25 | Buffer(); 26 | size_t* getLengthPtr(); 27 | static buffer_t* newBuf(); 28 | char operator[](int idx); 29 | char** getBufPtr(); // for compatiable c code. 30 | char* back(); 31 | char* begin(); 32 | char* end(); 33 | void clear(); 34 | void drop(size_t size); 35 | void bufRealloc(size_t size); 36 | std::unique_ptr duplicateDataToArray(); 37 | void copy(const uvw::DataEvent& event); 38 | void copy(const uvw::UDPDataEvent& event); 39 | void copyFromBegin(const uvw::DataEvent& event, int length = -1); 40 | void copyFromBegin(char* start, size_t size); 41 | void copy(const Buffer& that); 42 | void setLength(int l); 43 | size_t length(); 44 | void protocolPluginUDPPreEncrypt(UDPRelay& connectionContext); 45 | void protocolPluginUDPPostDecrypt(UDPRelay& connectionContext); 46 | void protocolPluginPreEncrypt(ObfsClass& obfsClass, ConnectionContext& connectionContext); 47 | void protocolPluginPostDecrypt(ObfsClass& obfsClass, ConnectionContext& connectionContext); 48 | int ssEncrypt(CipherEnv& cipherEnv, ConnectionContext& connectionContext); 49 | int ssDecrypt(CipherEnv& cipherEnv, ConnectionContext& connectionContext); 50 | int ssEncryptAll(CipherEnv& cipherEnv); 51 | int ssDecryptALl(CipherEnv& cipherEnv); 52 | void clientEncode(ObfsClass& obfsClass, ConnectionContext& connectionContext, int encodeLen = -1); 53 | int clientDecode(ObfsClass& obfsClass, ConnectionContext& connectionContext); 54 | size_t* getCapacityPtr(); 55 | 56 | public: 57 | static constexpr size_t BUF_DEFAULT_CAPACITY = 2048; 58 | 59 | private: 60 | std::unique_ptr buf; 61 | void copy(char* start, char* end); 62 | }; 63 | #endif // SSRUVBUFFER_H 64 | -------------------------------------------------------------------------------- /src/obfs/obfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs.h - Define shadowsocksR server's buffers and callbacks 3 | * 4 | * Copyright (C) 2015 - 2016, Break Wa11 5 | */ 6 | 7 | #ifndef _OBFS_OBFS_H 8 | #define _OBFS_OBFS_H 9 | 10 | #include "encrypt.h" 11 | 12 | #include 13 | #define OBFS_HMAC_SHA1_LEN 10 14 | 15 | #ifdef __cplusplus 16 | extern "C" 17 | { 18 | #endif 19 | typedef struct 20 | { 21 | char host[256]; 22 | uint16_t port; 23 | const char* param; 24 | void* g_data; 25 | uint8_t* iv; 26 | uint16_t iv_len; 27 | // uint8_t *recv_iv; 28 | uint16_t recv_iv_len; 29 | uint8_t* key; 30 | uint16_t key_len; 31 | int head_len; 32 | uint16_t tcp_mss; 33 | uint16_t overhead; 34 | uint32_t buffer_size; 35 | cipher_env_t* cipher_env; 36 | } server_info_t; 37 | 38 | typedef struct 39 | { 40 | server_info_t server; 41 | void* l_data; 42 | } obfs; 43 | 44 | typedef struct 45 | { 46 | void* (*init_data)(); 47 | 48 | obfs* (*new_obfs)(); 49 | 50 | int (*get_overhead)(obfs* self); 51 | 52 | void (*get_server_info)(obfs* self, server_info_t* server); 53 | 54 | void (*set_server_info)(obfs* self, server_info_t* server); 55 | 56 | void (*dispose)(obfs* self); 57 | 58 | int (*client_pre_encrypt)(obfs* self, char** pplaindata, int datalength, size_t* capacity); 59 | 60 | int (*client_encode)(obfs* self, char** pencryptdata, int datalength, size_t* capacity); 61 | 62 | int (*client_decode)(obfs* self, char** pencryptdata, int datalength, size_t* capacity, int* needsendback); 63 | 64 | int (*client_post_decrypt)(obfs* self, char** pplaindata, int datalength, size_t* capacity); 65 | 66 | int (*client_udp_pre_encrypt)(obfs* self, char** pplaindata, int datalength, size_t* capacity); 67 | 68 | int (*client_udp_post_decrypt)(obfs* self, char** pplaindata, int datalength, size_t* capacity); 69 | } obfs_class; 70 | 71 | obfs_class* new_obfs_class(const char* plugin_name); 72 | 73 | void free_obfs_class(obfs_class* plugin); 74 | 75 | void set_server_info(obfs* self, server_info_t* server); 76 | 77 | void get_server_info(obfs* self, server_info_t* server); 78 | 79 | obfs* new_obfs(); 80 | 81 | void dispose_obfs(obfs* self); 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | #endif // _OBFS_OBFS_H 87 | -------------------------------------------------------------------------------- /src/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cache.h - Define the cache manager interface 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the shadowsocks-libev. 7 | * 8 | * shadowsocks-libev is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * shadowsocks-libev is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with shadowsocks-libev; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | /* 24 | * Original Author: Oliver Lorenz (ol), olli@olorenz.org, https://olorenz.org 25 | * License: This is licensed under the same terms as uthash itself 26 | */ 27 | 28 | #ifndef _CACHE_ 29 | #define _CACHE_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | #include "uthash.h" 36 | typedef double ssr_tstamp; 37 | /** 38 | * A cache entry 39 | */ 40 | struct cache_entry 41 | { 42 | char* key; /** 5 | */ 6 | 7 | #ifndef _OBFS_AUTH_CHAIN_H 8 | #define _OBFS_AUTH_CHAIN_H 9 | 10 | #include "obfs.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | 17 | void* auth_chain_a_init_data(); 18 | 19 | void* auth_chain_b_init_data(); 20 | 21 | void* auth_chain_c_init_data(); 22 | 23 | void* auth_chain_d_init_data(); 24 | 25 | void* auth_chain_e_init_data(); 26 | 27 | void* auth_chain_f_init_data(); 28 | 29 | obfs* auth_chain_a_new_obfs(); 30 | 31 | obfs* auth_chain_b_new_obfs(); 32 | 33 | obfs* auth_chain_c_new_obfs(); 34 | 35 | obfs* auth_chain_d_new_obfs(); 36 | 37 | obfs* auth_chain_e_new_obfs(); 38 | 39 | obfs* auth_chain_f_new_obfs(); 40 | 41 | void auth_chain_a_dispose(obfs* self); 42 | 43 | void auth_chain_b_dispose(obfs* self); 44 | 45 | void auth_chain_c_dispose(obfs* self); 46 | 47 | void auth_chain_d_dispose(obfs* self); 48 | 49 | void auth_chain_e_dispose(obfs* self); 50 | 51 | void auth_chain_f_dispose(obfs* self); 52 | 53 | void auth_chain_a_set_server_info(obfs* self, server_info_t* server); 54 | 55 | void auth_chain_b_set_server_info(obfs* self, server_info_t* server); 56 | 57 | void auth_chain_c_set_server_info(obfs* self, server_info_t* server); 58 | 59 | void auth_chain_d_set_server_info(obfs* self, server_info_t* server); 60 | 61 | void auth_chain_e_set_server_info(obfs* self, server_info_t* server); 62 | 63 | void auth_chain_f_set_server_info(obfs* self, server_info_t* server); 64 | 65 | int auth_chain_a_client_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 66 | 67 | int auth_chain_a_client_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 68 | 69 | int auth_chain_a_client_udp_pre_encrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 70 | 71 | int auth_chain_a_client_udp_post_decrypt(obfs* self, char** pplaindata, int datalength, size_t* capacity); 72 | 73 | int auth_chain_a_get_overhead(obfs* self); 74 | 75 | int auth_chain_b_get_overhead(obfs* self); 76 | 77 | int auth_chain_c_get_overhead(obfs* self); 78 | 79 | int auth_chain_d_get_overhead(obfs* self); 80 | 81 | int auth_chain_e_get_overhead(obfs* self); 82 | 83 | int auth_chain_f_get_overhead(obfs* self); 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | #endif // _OBFS_AUTH_CHAIN_H 89 | -------------------------------------------------------------------------------- /src/UDPRelay.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHADOWSOCKSR_UVW_UDPRELAY_HPP 2 | #define SHADOWSOCKSR_UVW_UDPRELAY_HPP 3 | 4 | #include 5 | 6 | #include "uvw/loop.h" 7 | #include "uvw/udp.h" 8 | #include 9 | #include 10 | 11 | extern "C" 12 | { 13 | #include "encrypt.h" 14 | #include "obfs/obfs.h" 15 | #include "shadowsocksr.h" 16 | } 17 | class CipherEnv; 18 | class ObfsClass; 19 | class Buffer; 20 | class UDPConnectionContext; 21 | 22 | class UDPRelay 23 | { 24 | private: 25 | struct SockaddrHasher 26 | { 27 | // https://www.boost.org/doc/libs/1_72_0/boost/container_hash/hash.hpp 28 | std::size_t operator()(const uvw::Addr& s) const 29 | { 30 | std::hash strHasher; 31 | std::size_t h = strHasher(s.ip); 32 | h ^= std::hash {}(s.port) + 0x9e3779b9 + (h << 6) + (h >> 2); 33 | return h; 34 | } 35 | }; 36 | struct SockAddrEqual 37 | { 38 | bool operator()(const uvw::Addr& t1, const uvw::Addr& t2) const 39 | { 40 | return t1.ip == t2.ip && t1.port == t2.port; 41 | } 42 | }; 43 | 44 | int parseUDPRelayHeader(const char* buf, size_t buf_len, 45 | char* host, char* port, struct sockaddr_storage* storage); 46 | 47 | void remoteRecv(uvw::UDPDataEvent& data, uvw::UDPHandle& handle, const uvw::Addr& localSrcAddr); 48 | 49 | void panic(const uvw::Addr& addr); 50 | 51 | void serverRecv(uvw::UDPDataEvent& data, uvw::UDPHandle& handle); 52 | 53 | public: 54 | UDPRelay(std::shared_ptr loop, CipherEnv& cipherEnv, ObfsClass& obfsClass, const profile_t& profile); 55 | 56 | ~UDPRelay(); 57 | 58 | int initUDPRelay(int mtu, const char* host, int port, struct sockaddr_storage remote_addr); 59 | 60 | private: 61 | CipherEnv* cipherEnvPtr; 62 | 63 | public: 64 | std::unique_ptr protocol_plugin; 65 | std::unique_ptr protocolPtr; 66 | 67 | private: 68 | void* protocol_global = nullptr; 69 | int timeout; 70 | static constexpr int MAX_UDP_PACKET_SIZE = 65507; 71 | static constexpr int PACKET_HEADER_SIZE = 1 + 28 + 2 + 64; 72 | static constexpr int DEFAULT_PACKET_SIZE = 1492 - PACKET_HEADER_SIZE; //the default MTU for UDP relay 73 | std::unique_ptr localBuf; 74 | std::shared_ptr loop; 75 | std::shared_ptr udpServer; 76 | std::unordered_map, SockaddrHasher, SockAddrEqual> socketCache; 77 | int packet_size { DEFAULT_PACKET_SIZE }; 78 | int buf_size { DEFAULT_PACKET_SIZE * 2 }; 79 | sockaddr_storage remoteAddr {}; 80 | }; 81 | 82 | #endif //SHADOWSOCKSR_UVW_UDPRELAY_HPP 83 | -------------------------------------------------------------------------------- /src/SSRThread.cpp: -------------------------------------------------------------------------------- 1 | #include "SSRThread.hpp" 2 | #include "TCPRelay.hpp" 3 | SSRThread::SSRThread(int localPort, 4 | int remotePort, 5 | std::string local_addr, 6 | std::string remote_host, 7 | std::string method, 8 | std::string password, 9 | std::string obfs, 10 | std::string obfs_param, 11 | std::string protocol, 12 | std::string protocol_param) 13 | : localPort(localPort) 14 | , remotePort(remotePort) 15 | , local_addr(std::move(local_addr)) 16 | , remote_host(std::move(remote_host)) 17 | , method(std::move(method)) 18 | , password(std::move(password)) 19 | , obfs(std::move(obfs)) 20 | , obfs_param(std::move(obfs_param)) 21 | , protocol(std::move(protocol)) 22 | , protocol_param(std::move(protocol_param)) 23 | , tcpRelay(TCPRelay::create()) 24 | { 25 | } 26 | 27 | SSRThread::SSRThread(int localPort, 28 | int remotePort, 29 | int timeout, 30 | int mtu, 31 | SSR_WORK_MODE work_mode, 32 | std::string local_addr, 33 | std::string remote_host, 34 | std::string method, 35 | std::string password, 36 | std::string obfs, 37 | std::string obfs_param, 38 | std::string protocol, 39 | std::string protocol_param, 40 | int ipv6first, 41 | int verbose) 42 | : localPort(localPort) 43 | , remotePort(remotePort) 44 | , timeout(timeout) 45 | , mtu(mtu) 46 | , mode(static_cast(work_mode)) 47 | , local_addr(std::move(local_addr)) 48 | , remote_host(std::move(remote_host)) 49 | , method(std::move(method)) 50 | , password(std::move(password)) 51 | , obfs(std::move(obfs)) 52 | , obfs_param(std::move(obfs_param)) 53 | , protocol(std::move(protocol)) 54 | , protocol_param(std::move(protocol_param)) 55 | , ipv6first(ipv6first) 56 | , verbose(verbose) 57 | , tcpRelay(TCPRelay::create()) 58 | { 59 | } 60 | 61 | SSRThread::~SSRThread() 62 | { 63 | stop(); 64 | } 65 | 66 | void SSRThread::run() 67 | { 68 | profile_t profile; 69 | profile.remote_host = remote_host.data(); 70 | profile.local_addr = local_addr.empty() ? nullptr : local_addr.data(); 71 | profile.method = method.data(); 72 | profile.timeout = timeout; 73 | profile.password = password.data(); 74 | profile.obfs = obfs.data(); 75 | profile.obfs_param = obfs_param.data(); 76 | profile.protocol = protocol.data(); 77 | profile.protocol_param = protocol_param.data(); 78 | profile.remote_port = remotePort; 79 | profile.local_port = localPort; 80 | profile.mtu = mtu; 81 | profile.mode = mode; 82 | profile.acl = nullptr; 83 | profile.fast_open = 1; // libuv is not supported fastopen yet. 84 | profile.verbose = verbose; 85 | profile.ipv6first = ipv6first; 86 | tcpRelay->loopMain(profile); 87 | } 88 | 89 | void SSRThread::stop() 90 | { 91 | if (isRunning()) { 92 | tcpRelay->stop(); 93 | wait(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/obfs/obfsutil.c: -------------------------------------------------------------------------------- 1 | #include "obfsutil.h" 2 | 3 | #include "encrypt.h" 4 | 5 | #include 6 | #include 7 | 8 | int get_head_size(char* plaindata, int size, int def_size) 9 | { 10 | if (plaindata == NULL || size < 2) 11 | return def_size; 12 | int head_type = plaindata[0] & 0x7; 13 | if (head_type == 1) 14 | return 7; 15 | if (head_type == 4) 16 | return 19; 17 | if (head_type == 3) 18 | return 4 + plaindata[1]; 19 | return def_size; 20 | } 21 | 22 | static int shift128plus_init_flag = 0; 23 | static uint64_t shift128plus_s[2] = { 0x10000000, 0xFFFFFFFF }; 24 | 25 | void init_shift128plus(void) 26 | { 27 | if (shift128plus_init_flag == 0) { 28 | shift128plus_init_flag = 1; 29 | uint32_t seed = (uint32_t)time(NULL); 30 | shift128plus_s[0] = seed | 0x100000000L; 31 | shift128plus_s[1] = ((uint64_t)seed << 32) | 0x1; 32 | } 33 | } 34 | 35 | uint64_t xorshift128plus(void) 36 | { 37 | uint64_t x = shift128plus_s[0]; 38 | uint64_t const y = shift128plus_s[1]; 39 | shift128plus_s[0] = y; 40 | x ^= x << 23; // a 41 | x ^= x >> 17; // b 42 | x ^= y ^ (y >> 26); // c 43 | shift128plus_s[1] = x; 44 | return x + y; 45 | } 46 | 47 | int ss_md5_hmac(char* auth, char* msg, int msg_len, uint8_t* iv, int enc_iv_len, uint8_t* enc_key, int enc_key_len) 48 | { 49 | uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; 50 | memcpy(auth_key, iv, enc_iv_len); 51 | memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); 52 | return ss_md5_hmac_with_key(auth, msg, msg_len, auth_key, enc_iv_len + enc_key_len); 53 | } 54 | 55 | int ss_sha1_hmac(char* auth, char* msg, int msg_len, uint8_t* iv, int enc_iv_len, uint8_t* enc_key, int enc_key_len) 56 | { 57 | uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; 58 | memcpy(auth_key, iv, enc_iv_len); 59 | memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); 60 | return ss_sha1_hmac_with_key(auth, msg, msg_len, auth_key, enc_iv_len + enc_key_len); 61 | } 62 | 63 | int data_size_list_compare(const void* a, const void* b) 64 | { 65 | return (*(int*)a - *(int*)b); 66 | } 67 | 68 | int find_pos(int arr[], int length, int key) 69 | { 70 | int low = 0; 71 | int high = length - 1; 72 | int middle = -1; 73 | 74 | if (key > arr[high]) 75 | return length; 76 | 77 | while (low < high) { 78 | middle = (low + high) / 2; 79 | if (key > arr[middle]) { 80 | low = middle + 1; 81 | } else if (key <= arr[middle]) { 82 | high = middle; 83 | } 84 | } 85 | return low; 86 | } 87 | 88 | void memintcopy_lt(void* mem, uint32_t val) 89 | { 90 | ((uint8_t*)mem)[0] = (uint8_t)(val); 91 | ((uint8_t*)mem)[1] = (uint8_t)(val >> 8); 92 | ((uint8_t*)mem)[2] = (uint8_t)(val >> 16); 93 | ((uint8_t*)mem)[3] = (uint8_t)(val >> 24); 94 | } 95 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ---------------------------------------------------------------------- 3 | # Copyright © 2011-2015, RedJack, LLC. 4 | # All rights reserved. 5 | # 6 | # Please see the COPYING file in this distribution for license details. 7 | # ---------------------------------------------------------------------- 8 | 9 | cmake_minimum_required(VERSION 3.10) 10 | set(PROJECT_NAME shadowsocksr-uvw) 11 | project(${PROJECT_NAME}) 12 | set(VERSION 0.0.1) 13 | # Detect linux 14 | if (UNIX AND NOT APPLE) 15 | set(LINUX TRUE) 16 | endif () 17 | if(WIN32) 18 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 19 | if(CMAKE_CL_64) 20 | include(${CMAKE_SOURCE_DIR}/libs/x64-windows/scripts/buildsystems/vcpkg.cmake) 21 | else() 22 | include(${CMAKE_SOURCE_DIR}/libs/x86-windows/scripts/buildsystems/vcpkg.cmake) 23 | endif() 24 | endif() 25 | endif() 26 | add_compile_options($<$:/MP>) 27 | include(CTest) 28 | set(WITH_CRYPTO_LIBRARY "openssl" CACHE STRING "build with the given crypto library, TYPE=openssl|polarssl|mbedtls default=openssl") 29 | set(SSR_UVW_WITH_QT 1 CACHE BOOL "build with qt") 30 | option(BUILD_SODIUM_TESTING "build sodium testing when static link sodium" OFF) 31 | option(USE_SYSTEM_SODIUM "use system sodium" OFF) 32 | option(USE_SYSTEM_LIBUV "use system libuv" OFF) 33 | option(STATIC_LINK_LIBUV "static link libuv" ON) 34 | option(STATIC_LINK_SODIUM "static link libsodium" ON) 35 | if(NOT USE_SYSTEM_SODIUM AND NOT STATIC_LINK_SODIUM) 36 | message(FATAL_ERROR "Not support dynamic linking libsodium without using system libsodium!") 37 | endif() 38 | if(NOT USE_SYSTEM_LIBUV AND NOT STATIC_LINK_LIBUV) 39 | message(FATAL_ERROR "Not support dynamic linking libuv without using system libuv!") 40 | endif() 41 | 42 | 43 | if(NOT USE_SYSTEM_SODIUM) 44 | configure_file(cmake/souium.cmake ${CMAKE_CURRENT_SOURCE_DIR}/libsodium/CMakeLists.txt COPYONLY) 45 | if(NOT STATIC_LINK_SODIUM) 46 | add_definitions(-DSODIUM_BUILD_SHARED_LIBS) 47 | endif() 48 | add_subdirectory(libsodium EXCLUDE_FROM_ALL) 49 | set(sodium_LIBRARIES sodium::sodium) 50 | elseif(USE_SYSTEM_SODIUM AND STATIC_LINK_SODIUM) 51 | add_definitions(-Dsodium_USE_STATIC_LIBS) 52 | endif() 53 | if(NOT USE_SYSTEM_LIBUV) 54 | set(LibUV_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libuv/include) 55 | add_subdirectory(libuv EXCLUDE_FROM_ALL) 56 | if(STATIC_LINK_LIBUV) 57 | add_library(uv::uv-static ALIAS uv_a) 58 | set_target_properties(uv PROPERTIES EXCLUDE_FROM_ALL TRUE) 59 | set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1) 60 | set(LibUV_LIBRARIES uv::uv-static) 61 | else() 62 | add_library(uv::uv-shared ALIAS uv) 63 | set_target_properties(uv PROPERTIES POSITION_INDEPENDENT_CODE 1) 64 | set(LibUV_LIBRARIES uv::uv-shared) 65 | endif() 66 | endif() 67 | include ( cmake/dist.cmake ) 68 | include ( configure ) 69 | configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ) 70 | 71 | 72 | include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) 73 | 74 | add_subdirectory(src) 75 | if (BUILD_TESTING) 76 | message("build ssr uvw testing") 77 | add_subdirectory(test) 78 | endif () 79 | -------------------------------------------------------------------------------- /src/obfs/crc32.c: -------------------------------------------------------------------------------- 1 | #include "crc32.h" 2 | 3 | #include 4 | 5 | static uint32_t crc32_table[256] = { 0 }; 6 | 7 | void init_crc32_table(void) 8 | { 9 | uint32_t c, i, j; 10 | if (crc32_table[0] == 0) { 11 | for (i = 0; i < 256; i++) { 12 | c = i; 13 | for (j = 0; j < 8; j++) { 14 | if (c & 1) 15 | c = 0xedb88320L ^ (c >> 1); 16 | else 17 | c = c >> 1; 18 | } 19 | crc32_table[i] = c; 20 | } 21 | } 22 | } 23 | 24 | uint32_t crc32_ssr(unsigned char* buffer, unsigned int size) 25 | { 26 | uint32_t crc = 0xFFFFFFFF; 27 | unsigned int i; 28 | for (i = 0; i < size; i++) { 29 | crc = crc32_table[(crc ^ buffer[i]) & 0xFF] ^ (crc >> 8); 30 | } 31 | return crc ^ 0xFFFFFFFF; 32 | } 33 | 34 | void fillcrc32to(unsigned char* buffer, unsigned int size, unsigned char* outbuffer) 35 | { 36 | uint32_t crc = 0xFFFFFFFF; 37 | unsigned int i; 38 | for (i = 0; i < size; i++) { 39 | crc = crc32_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8); 40 | } 41 | crc ^= 0xFFFFFFFF; 42 | outbuffer[0] = (unsigned char)crc; 43 | outbuffer[1] = (unsigned char)(crc >> 8); 44 | outbuffer[2] = (unsigned char)(crc >> 16); 45 | outbuffer[3] = (unsigned char)(crc >> 24); 46 | } 47 | 48 | void fillcrc32(unsigned char* buffer, unsigned int size) 49 | { 50 | uint32_t crc = 0xFFFFFFFF; 51 | unsigned int i; 52 | size -= 4; 53 | for (i = 0; i < size; i++) { 54 | crc = crc32_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8); 55 | } 56 | buffer += size; 57 | buffer[0] = (unsigned char)crc; 58 | buffer[1] = (unsigned char)(crc >> 8); 59 | buffer[2] = (unsigned char)(crc >> 16); 60 | buffer[3] = (unsigned char)(crc >> 24); 61 | } 62 | 63 | void adler32_short(unsigned char* buffer, unsigned int size, uint32_t* a, uint32_t* b) 64 | { 65 | for (int i = 0; i < (int)size; i++) { 66 | *a += buffer[i]; 67 | *b += *a; 68 | } 69 | *a %= 65521; 70 | *b %= 65521; 71 | } 72 | 73 | #define NMAX 5552 74 | static uint32_t adler32(unsigned char* buffer, unsigned int size) 75 | { 76 | uint32_t a = 1; 77 | uint32_t b = 0; 78 | while (size >= NMAX) { 79 | adler32_short(buffer, NMAX, &a, &b); 80 | buffer += NMAX; 81 | size -= NMAX; 82 | } 83 | adler32_short(buffer, size, &a, &b); 84 | return (b << 16) + a; 85 | } 86 | #undef NMAX 87 | 88 | void filladler32(unsigned char* buffer, unsigned int size) 89 | { 90 | size -= 4; 91 | uint32_t checksum = adler32(buffer, size); 92 | buffer += size; 93 | buffer[0] = (unsigned char)checksum; 94 | buffer[1] = (unsigned char)(checksum >> 8); 95 | buffer[2] = (unsigned char)(checksum >> 16); 96 | buffer[3] = (unsigned char)(checksum >> 24); 97 | } 98 | 99 | int checkadler32(unsigned char* buffer, unsigned int size) 100 | { 101 | size -= 4; 102 | uint32_t checksum = adler32(buffer, size); 103 | buffer += size; 104 | return checksum == (((uint32_t)buffer[3] << 24) | ((uint32_t)buffer[2] << 16) | ((uint32_t)buffer[1] << 8) | (uint32_t)buffer[0]); 105 | } 106 | -------------------------------------------------------------------------------- /src/uvw/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TIMER_INCLUDE_H 2 | #define UVW_TIMER_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include "handle.hpp" 8 | #include "loop.h" 9 | 10 | 11 | namespace uvw { 12 | 13 | 14 | /** 15 | * @brief TimerEvent event. 16 | * 17 | * It will be emitted by TimerHandle according with its functionalities. 18 | */ 19 | struct TimerEvent {}; 20 | 21 | 22 | /** 23 | * @brief The TimerHandle handle. 24 | * 25 | * Timer handles are used to schedule events to be emitted in the future. 26 | * 27 | * To create a `TimerHandle` through a `Loop`, no arguments are required. 28 | */ 29 | class TimerHandle final: public Handle { 30 | static void startCallback(uv_timer_t *handle); 31 | 32 | public: 33 | using Time = std::chrono::duration; 34 | 35 | using Handle::Handle; 36 | 37 | /** 38 | * @brief Initializes the handle. 39 | * @return True in case of success, false otherwise. 40 | */ 41 | bool init(); 42 | 43 | /** 44 | * @brief Starts the timer. 45 | * 46 | * If timeout is zero, a TimerEvent event is emitted on the next event loop 47 | * iteration. If repeat is non-zero, a TimerEvent event is emitted first 48 | * after timeout milliseconds and then repeatedly after repeat milliseconds. 49 | * 50 | * @param timeout Milliseconds before to emit an event (use 51 | * `std::chrono::duration`). 52 | * @param repeat Milliseconds between successive events (use 53 | * `std::chrono::duration`). 54 | */ 55 | void start(Time timeout, Time repeat); 56 | 57 | /** 58 | * @brief Stops the handle. 59 | */ 60 | void stop(); 61 | 62 | /** 63 | * @brief Stops the timer and restarts it if it was repeating. 64 | * 65 | * Stop the timer, and if it is repeating restart it using the repeat value 66 | * as the timeout.
67 | * If the timer has never been started before it emits an ErrorEvent event. 68 | */ 69 | void again(); 70 | 71 | /** 72 | * @brief Sets the repeat interval value. 73 | * 74 | * The timer will be scheduled to run on the given interval and will follow 75 | * normal timer semantics in the case of a time-slice overrun.
76 | * For example, if a 50ms repeating timer first runs for 17ms, it will be 77 | * scheduled to run again 33ms later. If other tasks consume more than the 78 | * 33ms following the first timer event, then another event will be emitted 79 | * as soon as possible. 80 | * 81 | * If the repeat value is set from a listener bound to an event, it does 82 | * not immediately take effect. If the timer was non-repeating before, it 83 | * will have been stopped. If it was repeating, then the old repeat value 84 | * will have been used to schedule the next timeout. 85 | * 86 | * @param repeat Repeat interval in milliseconds (use 87 | * `std::chrono::duration`). 88 | */ 89 | void repeat(Time repeat); 90 | 91 | /** 92 | * @brief Gets the timer repeat value. 93 | * @return Timer repeat value in milliseconds (as a 94 | * `std::chrono::duration`). 95 | */ 96 | Time repeat(); 97 | }; 98 | 99 | 100 | } 101 | 102 | 103 | #ifndef UVW_AS_LIB 104 | #include "timer.cpp" 105 | #endif 106 | 107 | #endif // UVW_TIMER_INCLUDE_H 108 | -------------------------------------------------------------------------------- /test/src/TestDualStack.cpp: -------------------------------------------------------------------------------- 1 | #include "uvw/tcp.h" 2 | #include 3 | #define CATCH_CONFIG_MAIN 4 | #include "catch.hpp" 5 | 6 | TEST_CASE("Dual-Stack", "[tcp]") 7 | { 8 | auto loop = uvw::Loop::create(); 9 | 10 | auto tcpServer = loop->resource(); 11 | struct sockaddr_in6 sin6; 12 | sin6.sin6_family = AF_INET6; 13 | sin6.sin6_addr = in6addr_any; 14 | sin6.sin6_port = htons(10000); 15 | auto client1 = loop->resource(); 16 | auto client2 = loop->resource(); 17 | int client_count = 0; 18 | tcpServer->on([&client_count](const uvw::ListenEvent&, uvw::TCPHandle& handle) { 19 | std::shared_ptr socket = handle.loop().resource(); 20 | 21 | socket->on([](const uvw::ErrorEvent&, uvw::TCPHandle&) { FAIL(); }); 22 | socket->on([&handle](const uvw::CloseEvent&, uvw::TCPHandle&) { handle.close(); }); 23 | socket->on([](const uvw::EndEvent&, uvw::TCPHandle& sock) { sock.close(); }); 24 | 25 | handle.accept(*socket); 26 | socket->read(); 27 | client_count += 1; 28 | std::cout << "peer:" << socket->peer().ip << std::endl; 29 | }); 30 | 31 | client1->once([](const uvw::ConnectEvent&, uvw::TCPHandle& handle) { 32 | handle.close(); 33 | }); 34 | client2->once([](const uvw::ConnectEvent&, uvw::TCPHandle& handle) { 35 | handle.close(); 36 | }); 37 | tcpServer->bind(reinterpret_cast(sin6)); 38 | tcpServer->listen(); 39 | client1->connect("127.0.0.1", 10000); 40 | client2->connect("::1", 10000); 41 | loop->run(); 42 | REQUIRE(client_count == 2); 43 | } 44 | 45 | TEST_CASE("Single-Stack", "[tcp]") 46 | { 47 | auto loop = uvw::Loop::create(); 48 | auto tcpServer = loop->resource(); 49 | struct sockaddr_in6 sin6; 50 | sin6.sin6_family = AF_INET6; 51 | sin6.sin6_addr = in6addr_loopback; 52 | sin6.sin6_port = htons(10000); 53 | auto client1 = loop->resource(); 54 | auto client2 = loop->resource(); 55 | int client_count = 0; 56 | tcpServer->on([&client_count](const uvw::ListenEvent&, uvw::TCPHandle& handle) { 57 | std::shared_ptr socket = handle.loop().resource(); 58 | 59 | socket->on([](const uvw::ErrorEvent&, uvw::TCPHandle&) { FAIL(); }); 60 | socket->on([&handle](const uvw::CloseEvent&, uvw::TCPHandle&) { handle.close(); }); 61 | socket->on([](const uvw::EndEvent&, uvw::TCPHandle& sock) { sock.close(); }); 62 | 63 | handle.accept(*socket); 64 | socket->read(); 65 | client_count += 1; 66 | std::cout << "peer:" << socket->peer().ip << std::endl; 67 | }); 68 | 69 | client1->once([](auto&, uvw::TCPHandle& handle) { 70 | handle.close(); 71 | }); 72 | client1->once([](const uvw::ConnectEvent&, uvw::TCPHandle& handle) { 73 | handle.close(); 74 | }); 75 | client2->once([](const uvw::ConnectEvent&, uvw::TCPHandle& handle) { 76 | handle.close(); 77 | }); 78 | tcpServer->bind(reinterpret_cast(sin6)); 79 | tcpServer->listen(); 80 | client1->connect("127.0.0.1", 10000); 81 | client2->connect("::1", 10000); 82 | loop->run(); 83 | REQUIRE(client_count == 1); 84 | } 85 | -------------------------------------------------------------------------------- /src/uvw/process.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "process.h" 3 | #endif 4 | #include 5 | 6 | #include "config.h" 7 | 8 | 9 | namespace uvw { 10 | 11 | 12 | UVW_INLINE ExitEvent::ExitEvent(int64_t code, int sig) noexcept 13 | : status{code}, signal{sig} 14 | {} 15 | 16 | 17 | UVW_INLINE void ProcessHandle::exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) { 18 | ProcessHandle &process = *(static_cast(handle->data)); 19 | process.publish(ExitEvent{exitStatus, termSignal}); 20 | } 21 | 22 | 23 | UVW_INLINE ProcessHandle::ProcessHandle(ConstructorAccess ca, std::shared_ptr ref) 24 | : Handle{ca, std::move(ref)} 25 | {} 26 | 27 | 28 | UVW_INLINE void ProcessHandle::disableStdIOInheritance() noexcept { 29 | uv_disable_stdio_inheritance(); 30 | } 31 | 32 | 33 | UVW_INLINE bool ProcessHandle::kill(int pid, int signum) noexcept { 34 | return (0 == uv_kill(pid, signum)); 35 | } 36 | 37 | 38 | UVW_INLINE bool ProcessHandle::init() { 39 | // deferred initialization: libuv initializes process handles only when 40 | // uv_spawn is invoked and uvw stays true to the underlying library 41 | return true; 42 | } 43 | 44 | 45 | UVW_INLINE void ProcessHandle::spawn(const char *file, char **args, char **env) { 46 | uv_process_options_t po; 47 | 48 | po.exit_cb = &exitCallback; 49 | po.file = file; 50 | po.args = args; 51 | po.env = env; 52 | po.cwd = poCwd.empty() ? nullptr : poCwd.data(); 53 | po.flags = poFlags; 54 | po.uid = poUid; 55 | po.gid = poGid; 56 | 57 | std::vector poStdio; 58 | poStdio.reserve(poFdStdio.size() + poStreamStdio.size()); 59 | poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend()); 60 | poStdio.insert(poStdio.end(), poStreamStdio.cbegin(), poStreamStdio.cend()); 61 | 62 | po.stdio_count = static_cast(poStdio.size()); 63 | po.stdio = poStdio.data(); 64 | 65 | // fake initialization so as to have leak invoked 66 | // see init member function for more details 67 | initialize([](auto...) { 68 | return 0; 69 | }); 70 | 71 | invoke(&uv_spawn, parent(), get(), &po); 72 | } 73 | 74 | 75 | UVW_INLINE void ProcessHandle::kill(int signum) { 76 | invoke(&uv_process_kill, get(), signum); 77 | } 78 | 79 | 80 | UVW_INLINE int ProcessHandle::pid() noexcept { 81 | return get()->pid; 82 | } 83 | 84 | 85 | UVW_INLINE ProcessHandle &ProcessHandle::cwd(std::string path) noexcept { 86 | poCwd = path; 87 | return *this; 88 | } 89 | 90 | 91 | UVW_INLINE ProcessHandle &ProcessHandle::flags(Flags flags) noexcept { 92 | poFlags = flags; 93 | return *this; 94 | } 95 | 96 | 97 | UVW_INLINE ProcessHandle &ProcessHandle::stdio(FileHandle fd, Flags flags) { 98 | auto fgs = static_cast(Flags::Type{flags}); 99 | 100 | auto actual = FileHandle::Type{fd}; 101 | 102 | auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container) { 103 | return container.data.fd == actual; 104 | }); 105 | 106 | if(it == poFdStdio.cend()) { 107 | uv_stdio_container_t container; 108 | container.flags = fgs; 109 | container.data.fd = actual; 110 | poFdStdio.push_back(std::move(container)); 111 | } else { 112 | it->flags = fgs; 113 | it->data.fd = actual; 114 | } 115 | 116 | return *this; 117 | } 118 | 119 | 120 | UVW_INLINE ProcessHandle &ProcessHandle::uid(Uid id) { 121 | poUid = id; 122 | return *this; 123 | } 124 | 125 | 126 | UVW_INLINE ProcessHandle &ProcessHandle::gid(Gid id) { 127 | poGid = id; 128 | return *this; 129 | } 130 | 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/win/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef __GETOPT_H__ 2 | /** 3 | * DISCLAIMER 4 | * This file has no copyright assigned and is placed in the Public Domain. 5 | * This file is a part of the w64 mingw-runtime package. 6 | * 7 | * The w64 mingw-runtime package and its code is distributed in the hope that it 8 | * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR 9 | * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to 10 | * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #define __GETOPT_H__ 14 | 15 | /* All the headers include this file. */ 16 | #include 17 | 18 | #if defined( WINGETOPT_SHARED_LIB ) 19 | # if defined( BUILDING_WINGETOPT_DLL ) 20 | # define WINGETOPT_API __declspec(dllexport) 21 | # else 22 | # define WINGETOPT_API __declspec(dllimport) 23 | # endif 24 | #else 25 | # define WINGETOPT_API 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | WINGETOPT_API extern int optind; /* index of first non-option in argv */ 33 | WINGETOPT_API extern int optopt; /* single option character, as parsed */ 34 | WINGETOPT_API extern int opterr; /* flag to enable built-in diagnostics... */ 35 | /* (user may set to zero, to suppress) */ 36 | 37 | WINGETOPT_API extern char *optarg; /* pointer to argument of current option */ 38 | 39 | extern int getopt(int nargc, char * const *nargv, const char *options); 40 | 41 | #ifdef _BSD_SOURCE 42 | /* 43 | * BSD adds the non-standard `optreset' feature, for reinitialisation 44 | * of `getopt' parsing. We support this feature, for applications which 45 | * proclaim their BSD heritage, before including this header; however, 46 | * to maintain portability, developers are advised to avoid it. 47 | */ 48 | # define optreset __mingw_optreset 49 | extern int optreset; 50 | #endif 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | /* 55 | * POSIX requires the `getopt' API to be specified in `unistd.h'; 56 | * thus, `unistd.h' includes this header. However, we do not want 57 | * to expose the `getopt_long' or `getopt_long_only' APIs, when 58 | * included in this manner. Thus, close the standard __GETOPT_H__ 59 | * declarations block, and open an additional __GETOPT_LONG_H__ 60 | * specific block, only when *not* __UNISTD_H_SOURCED__, in which 61 | * to declare the extended API. 62 | */ 63 | #endif /* !defined(__GETOPT_H__) */ 64 | 65 | #if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) 66 | #define __GETOPT_LONG_H__ 67 | 68 | #ifdef __cplusplus 69 | extern "C" { 70 | #endif 71 | 72 | struct option /* specification for a long form option... */ 73 | { 74 | const char *name; /* option name, without leading hyphens */ 75 | int has_arg; /* does it take an argument? */ 76 | int *flag; /* where to save its status, or NULL */ 77 | int val; /* its associated status value */ 78 | }; 79 | 80 | enum /* permitted values for its `has_arg' field... */ 81 | { 82 | no_argument = 0, /* option never takes an argument */ 83 | required_argument, /* option always requires an argument */ 84 | optional_argument /* option may take an argument */ 85 | }; 86 | 87 | extern int getopt_long(int nargc, char * const *nargv, const char *options, 88 | const struct option *long_options, int *idx); 89 | extern int getopt_long_only(int nargc, char * const *nargv, const char *options, 90 | const struct option *long_options, int *idx); 91 | /* 92 | * Previous MinGW implementation had... 93 | */ 94 | #ifndef HAVE_DECL_GETOPT 95 | /* 96 | * ...for the long form API only; keep this for compatibility. 97 | */ 98 | # define HAVE_DECL_GETOPT 1 99 | #endif 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ 106 | -------------------------------------------------------------------------------- /src/uvw/tcp.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "tcp.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE TCPHandle::TCPHandle(ConstructorAccess ca, std::shared_ptr ref, unsigned int f) 12 | : StreamHandle{ca, std::move(ref)}, tag{f ? FLAGS : DEFAULT}, flags{f} 13 | {} 14 | 15 | 16 | UVW_INLINE bool TCPHandle::init() { 17 | return (tag == FLAGS) ? initialize(&uv_tcp_init_ex, flags) : initialize(&uv_tcp_init); 18 | } 19 | 20 | 21 | UVW_INLINE void TCPHandle::open(OSSocketHandle socket) { 22 | invoke(&uv_tcp_open, get(), socket); 23 | } 24 | 25 | 26 | UVW_INLINE bool TCPHandle::noDelay(bool value) { 27 | return (0 == uv_tcp_nodelay(get(), value)); 28 | } 29 | 30 | 31 | UVW_INLINE bool TCPHandle::keepAlive(bool enable, TCPHandle::Time time) { 32 | return (0 == uv_tcp_keepalive(get(), enable, time.count())); 33 | } 34 | 35 | 36 | UVW_INLINE bool TCPHandle::simultaneousAccepts(bool enable) { 37 | return (0 == uv_tcp_simultaneous_accepts(get(), enable)); 38 | } 39 | 40 | 41 | UVW_INLINE void TCPHandle::bind(const sockaddr &addr, Flags opts) { 42 | invoke(&uv_tcp_bind, get(), &addr, opts); 43 | } 44 | 45 | 46 | template 47 | UVW_INLINE void TCPHandle::bind(std::string ip, unsigned int port, Flags opts) 48 | { 49 | typename details::IpTraits::Type addr; 50 | details::IpTraits::addrFunc(ip.data(), port, &addr); 51 | bind(reinterpret_cast(addr), std::move(opts)); 52 | } 53 | 54 | 55 | template 56 | UVW_INLINE void TCPHandle::bind(Addr addr, Flags opts) { 57 | bind(std::move(addr.ip), addr.port, std::move(opts)); 58 | } 59 | 60 | 61 | template 62 | UVW_INLINE Addr TCPHandle::sock() const noexcept { 63 | return details::address(&uv_tcp_getsockname, get()); 64 | } 65 | 66 | 67 | template 68 | UVW_INLINE Addr TCPHandle::peer() const noexcept { 69 | return details::address(&uv_tcp_getpeername, get()); 70 | } 71 | 72 | 73 | template 74 | UVW_INLINE void TCPHandle::connect(std::string ip, unsigned int port) { 75 | typename details::IpTraits::Type addr; 76 | details::IpTraits::addrFunc(ip.data(), port, &addr); 77 | connect(reinterpret_cast(addr)); 78 | } 79 | 80 | 81 | template 82 | UVW_INLINE void TCPHandle::connect(Addr addr) { 83 | connect(std::move(addr.ip), addr.port); 84 | } 85 | 86 | 87 | UVW_INLINE void TCPHandle::connect(const sockaddr &addr) { 88 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 89 | ptr->publish(event); 90 | }; 91 | 92 | auto req = loop().resource(); 93 | req->once(listener); 94 | req->once(listener); 95 | req->connect(&uv_tcp_connect, get(), &addr); 96 | } 97 | 98 | 99 | UVW_INLINE void TCPHandle::closeReset() { 100 | invoke(&uv_tcp_close_reset, get(), &this->closeCallback); 101 | } 102 | 103 | 104 | // explicit instantiations 105 | 106 | template void TCPHandle::bind(std::string, unsigned int, Flags); 107 | template void TCPHandle::bind(std::string, unsigned int, Flags); 108 | 109 | template void TCPHandle::bind(Addr, Flags); 110 | template void TCPHandle::bind(Addr, Flags); 111 | 112 | template Addr TCPHandle::sock() const noexcept; 113 | template Addr TCPHandle::sock() const noexcept; 114 | 115 | template Addr TCPHandle::peer() const noexcept; 116 | template Addr TCPHandle::peer() const noexcept; 117 | 118 | template void TCPHandle::connect(std::string, unsigned int); 119 | template void TCPHandle::connect(std::string, unsigned int); 120 | 121 | template void TCPHandle::connect(Addr addr); 122 | template void TCPHandle::connect(Addr addr); 123 | 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/uvw/underlying_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_UNDERLYING_TYPE_INCLUDE_H 2 | #define UVW_UNDERLYING_TYPE_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "loop.h" 9 | 10 | 11 | namespace uvw { 12 | 13 | 14 | /** 15 | * @brief Wrapper class for underlying types. 16 | * 17 | * It acts mainly as a wrapper around data structures of the underlying library. 18 | */ 19 | template 20 | class UnderlyingType { 21 | template 22 | friend class UnderlyingType; 23 | 24 | protected: 25 | struct ConstructorAccess { explicit ConstructorAccess(int) {} }; 26 | 27 | template 28 | auto get() noexcept { 29 | return reinterpret_cast(&resource); 30 | } 31 | 32 | template 33 | auto get() const noexcept { 34 | return reinterpret_cast(&resource); 35 | } 36 | 37 | template 38 | auto get(UnderlyingType &other) noexcept { 39 | return reinterpret_cast(&other.resource); 40 | } 41 | 42 | public: 43 | explicit UnderlyingType(ConstructorAccess, std::shared_ptr ref) noexcept 44 | : pLoop{std::move(ref)}, resource{} 45 | {} 46 | 47 | UnderlyingType(const UnderlyingType &) = delete; 48 | UnderlyingType(UnderlyingType &&) = delete; 49 | 50 | virtual ~UnderlyingType() { 51 | static_assert(std::is_base_of_v, T>); 52 | } 53 | 54 | UnderlyingType & operator=(const UnderlyingType &) = delete; 55 | UnderlyingType & operator=(UnderlyingType &&) = delete; 56 | 57 | /** 58 | * @brief Creates a new resource of the given type. 59 | * @param args Arguments to be forwarded to the actual constructor (if any). 60 | * @return A pointer to the newly created resource. 61 | */ 62 | template 63 | static std::shared_ptr create(Args&&... args) { 64 | return std::make_shared(ConstructorAccess{0}, std::forward(args)...); 65 | } 66 | 67 | /** 68 | * @brief Gets the loop from which the resource was originated. 69 | * @return A reference to a loop instance. 70 | */ 71 | Loop & loop() const noexcept { return *pLoop; } 72 | 73 | /** 74 | * @brief Gets the underlying raw data structure. 75 | * 76 | * This function should not be used, unless you know exactly what you are 77 | * doing and what are the risks.
78 | * Going raw is dangerous, mainly because the lifetime management of a loop, 79 | * a handle or a request is in charge to the library itself and users should 80 | * not work around it. 81 | * 82 | * @warning 83 | * Use this function at your own risk, but do not expect any support in case 84 | * of bugs. 85 | * 86 | * @return The underlying raw data structure. 87 | */ 88 | const U * raw() const noexcept { 89 | return &resource; 90 | } 91 | 92 | /** 93 | * @brief Gets the underlying raw data structure. 94 | * 95 | * This function should not be used, unless you know exactly what you are 96 | * doing and what are the risks.
97 | * Going raw is dangerous, mainly because the lifetime management of a loop, 98 | * a handle or a request is in charge to the library itself and users should 99 | * not work around it. 100 | * 101 | * @warning 102 | * Use this function at your own risk, but do not expect any support in case 103 | * of bugs. 104 | * 105 | * @return The underlying raw data structure. 106 | */ 107 | U * raw() noexcept { 108 | return const_cast(const_cast(this)->raw()); 109 | } 110 | 111 | private: 112 | std::shared_ptr pLoop; 113 | U resource; 114 | }; 115 | 116 | 117 | } 118 | 119 | #endif // UVW_UNDERLYING_TYPE_INCLUDE_H 120 | -------------------------------------------------------------------------------- /src/uvw/loop.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "loop.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE Loop::Loop(std::unique_ptr ptr) noexcept 12 | : loop{std::move(ptr)} 13 | {} 14 | 15 | 16 | UVW_INLINE std::shared_ptr Loop::create() { 17 | auto ptr = std::unique_ptr{new uv_loop_t, [](uv_loop_t *l) { 18 | delete l; 19 | }}; 20 | 21 | auto loop = std::shared_ptr{new Loop{std::move(ptr)}}; 22 | 23 | if(uv_loop_init(loop->loop.get())) { 24 | loop = nullptr; 25 | } 26 | 27 | return loop; 28 | } 29 | 30 | 31 | UVW_INLINE std::shared_ptr Loop::create(uv_loop_t *loop) { 32 | auto ptr = std::unique_ptr{loop, [](uv_loop_t *) {}}; 33 | return std::shared_ptr{new Loop{std::move(ptr)}}; 34 | } 35 | 36 | 37 | UVW_INLINE std::shared_ptr Loop::getDefault() { 38 | static std::weak_ptr ref; 39 | std::shared_ptr loop; 40 | 41 | if(ref.expired()) { 42 | auto def = uv_default_loop(); 43 | 44 | if(def) { 45 | auto ptr = std::unique_ptr(def, [](uv_loop_t *) {}); 46 | loop = std::shared_ptr{new Loop{std::move(ptr)}}; 47 | } 48 | 49 | ref = loop; 50 | } else { 51 | loop = ref.lock(); 52 | } 53 | 54 | return loop; 55 | } 56 | 57 | 58 | UVW_INLINE Loop::~Loop() noexcept { 59 | if(loop) { 60 | close(); 61 | } 62 | } 63 | 64 | 65 | UVW_INLINE void Loop::close() { 66 | auto err = uv_loop_close(loop.get()); 67 | return err ? publish(ErrorEvent{err}) : loop.reset(); 68 | } 69 | 70 | 71 | template 72 | bool Loop::run() noexcept { 73 | auto utm = static_cast>(mode); 74 | auto uvrm = static_cast(utm); 75 | return (uv_run(loop.get(), uvrm) == 0); 76 | } 77 | 78 | 79 | UVW_INLINE bool Loop::alive() const noexcept { 80 | return !(uv_loop_alive(loop.get()) == 0); 81 | } 82 | 83 | 84 | UVW_INLINE void Loop::stop() noexcept { 85 | uv_stop(loop.get()); 86 | } 87 | 88 | 89 | UVW_INLINE int Loop::descriptor() const noexcept { 90 | return uv_backend_fd(loop.get()); 91 | } 92 | 93 | 94 | UVW_INLINE std::pair Loop::timeout() const noexcept { 95 | auto to = uv_backend_timeout(loop.get()); 96 | return std::make_pair(to == -1, Time{to}); 97 | } 98 | 99 | 100 | UVW_INLINE Loop::Time Loop::now() const noexcept { 101 | return Time{uv_now(loop.get())}; 102 | } 103 | 104 | 105 | UVW_INLINE void Loop::update() const noexcept { 106 | return uv_update_time(loop.get()); 107 | } 108 | 109 | 110 | UVW_INLINE void Loop::walk(std::function callback) { 111 | // remember: non-capturing lambdas decay to pointers to functions 112 | uv_walk(loop.get(), [](uv_handle_t *handle, void *func) { 113 | BaseHandle &ref = *static_cast(handle->data); 114 | std::function &f = *static_cast *>(func); 115 | f(ref); 116 | }, &callback); 117 | } 118 | 119 | 120 | UVW_INLINE void Loop::fork() noexcept { 121 | auto err = uv_loop_fork(loop.get()); 122 | 123 | if(err) { 124 | publish(ErrorEvent{err}); 125 | } 126 | } 127 | 128 | 129 | UVW_INLINE void Loop::data(std::shared_ptr uData) { 130 | userData = std::move(uData); 131 | } 132 | 133 | 134 | UVW_INLINE const uv_loop_t *Loop::raw() const noexcept { 135 | return loop.get(); 136 | } 137 | 138 | 139 | UVW_INLINE uv_loop_t *Loop::raw() noexcept { 140 | return const_cast(const_cast(this)->raw()); 141 | } 142 | 143 | 144 | // explicit instantiations 145 | 146 | template bool Loop::run() noexcept; 147 | template bool Loop::run() noexcept; 148 | template bool Loop::run() noexcept; 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /cmake/CheckDIRSymbolExists.cmake: -------------------------------------------------------------------------------- 1 | # - Check if the DIR symbol exists like in AC_HEADER_DIRENT. 2 | # CHECK_DIRSYMBOL_EXISTS(FILES VARIABLE) 3 | # 4 | # FILES - include files to check 5 | # VARIABLE - variable to return result 6 | # 7 | # This module is a small but important variation on CheckSymbolExists.cmake. 8 | # The symbol always searched for is DIR, and the test programme follows 9 | # the AC_HEADER_DIRENT test programme rather than the CheckSymbolExists.cmake 10 | # test programme which always fails since DIR tends to be typedef'd 11 | # rather than #define'd. 12 | # 13 | # The following variables may be set before calling this macro to 14 | # modify the way the check is run: 15 | # 16 | # CMAKE_REQUIRED_FLAGS = string of compile command line flags 17 | # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) 18 | # CMAKE_REQUIRED_INCLUDES = list of include directories 19 | # CMAKE_REQUIRED_LIBRARIES = list of libraries to link 20 | 21 | MACRO(CHECK_DIRSYMBOL_EXISTS FILES VARIABLE) 22 | IF(NOT DEFINED ${VARIABLE}) 23 | SET(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n") 24 | SET(MACRO_CHECK_DIRSYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS}) 25 | IF(CMAKE_REQUIRED_LIBRARIES) 26 | SET(CHECK_DIRSYMBOL_EXISTS_LIBS 27 | "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") 28 | ELSE(CMAKE_REQUIRED_LIBRARIES) 29 | SET(CHECK_DIRSYMBOL_EXISTS_LIBS) 30 | ENDIF(CMAKE_REQUIRED_LIBRARIES) 31 | IF(CMAKE_REQUIRED_INCLUDES) 32 | SET(CMAKE_DIRSYMBOL_EXISTS_INCLUDES 33 | "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") 34 | ELSE(CMAKE_REQUIRED_INCLUDES) 35 | SET(CMAKE_DIRSYMBOL_EXISTS_INCLUDES) 36 | ENDIF(CMAKE_REQUIRED_INCLUDES) 37 | FOREACH(FILE ${FILES}) 38 | SET(CMAKE_CONFIGURABLE_FILE_CONTENT 39 | "${CMAKE_CONFIGURABLE_FILE_CONTENT}#include <${FILE}>\n") 40 | ENDFOREACH(FILE) 41 | SET(CMAKE_CONFIGURABLE_FILE_CONTENT 42 | "${CMAKE_CONFIGURABLE_FILE_CONTENT}\nint main()\n{if ((DIR *) 0) return 0;}\n") 43 | 44 | CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" 45 | "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckDIRSymbolExists.c" @ONLY) 46 | 47 | MESSAGE(STATUS "Looking for DIR in ${FILES}") 48 | TRY_COMPILE(${VARIABLE} 49 | ${CMAKE_BINARY_DIR} 50 | ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckDIRSymbolExists.c 51 | COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} 52 | CMAKE_FLAGS 53 | -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_DIRSYMBOL_EXISTS_FLAGS} 54 | "${CHECK_DIRSYMBOL_EXISTS_LIBS}" 55 | "${CMAKE_DIRSYMBOL_EXISTS_INCLUDES}" 56 | OUTPUT_VARIABLE OUTPUT) 57 | IF(${VARIABLE}) 58 | MESSAGE(STATUS "Looking for DIR in ${FILES} - found") 59 | SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol DIR") 60 | FILE(APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeOutput.log 61 | "Determining if the DIR symbol is defined as in AC_HEADER_DIRENT " 62 | "passed with the following output:\n" 63 | "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckDIRSymbolExists.c:\n" 64 | "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") 65 | ELSE(${VARIABLE}) 66 | MESSAGE(STATUS "Looking for DIR in ${FILES} - not found.") 67 | SET(${VARIABLE} "" CACHE INTERNAL "Have symbol DIR") 68 | FILE(APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log 69 | "Determining if the DIR symbol is defined as in AC_HEADER_DIRENT " 70 | "failed with the following output:\n" 71 | "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckDIRSymbolExists.c:\n" 72 | "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") 73 | ENDIF(${VARIABLE}) 74 | ENDIF(NOT DEFINED ${VARIABLE}) 75 | ENDMACRO(CHECK_DIRSYMBOL_EXISTS) 76 | -------------------------------------------------------------------------------- /test/src/TestBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "uvw/tcp.h" 2 | #include "uvw/udp.h" 3 | #include 4 | #define CATCH_CONFIG_MAIN 5 | #include "catch.hpp" 6 | 7 | TEST_CASE("newBuf", "[BufferTest]") 8 | { 9 | auto freeBuf = [](buffer_t* buf) { 10 | free(buf->array); 11 | free(buf); 12 | }; 13 | auto buf = std::unique_ptr(Buffer::newBuf(), freeBuf); 14 | REQUIRE(buf->capacity == Buffer::BUF_DEFAULT_CAPACITY); 15 | REQUIRE(buf->len == 0); 16 | REQUIRE(buf->idx == 0); 17 | } 18 | 19 | TEST_CASE("drop", "[BufferTest]") 20 | { 21 | auto buf = Buffer(); 22 | auto begin = buf.begin(); 23 | auto back = buf.back(); 24 | REQUIRE(begin == back); 25 | char a[] { 0x05, 0x00, 0x01, 0x03 }; 26 | buf.copyFromBegin(a, 4); 27 | REQUIRE(buf.length() == 4); 28 | REQUIRE(buf.back() == begin + 4); 29 | buf.drop(3); 30 | REQUIRE(*buf.begin() == 0x03); 31 | buf.drop(1); 32 | REQUIRE(buf.length() == 0); 33 | //no data to drop 34 | buf.drop(20); 35 | REQUIRE(buf.begin() == buf.back()); 36 | REQUIRE(buf.length() == 0); 37 | buf.copyFromBegin(a, 4); 38 | REQUIRE(buf.length() == 4); 39 | REQUIRE(*buf.getCapacityPtr() == Buffer::BUF_DEFAULT_CAPACITY); 40 | buf.setLength(0); 41 | REQUIRE(buf.length() == 0); 42 | } 43 | 44 | TEST_CASE("BufRealloc", "[BufferTest]") 45 | { 46 | auto buf = Buffer(); 47 | char a[Buffer::BUF_DEFAULT_CAPACITY]; 48 | buf.copyFromBegin(a, Buffer::BUF_DEFAULT_CAPACITY); 49 | buf.bufRealloc(2045); 50 | REQUIRE(buf.length() == 2045); 51 | REQUIRE(*buf.getCapacityPtr() == 2045); 52 | } 53 | TEST_CASE("DuplicatDataToArray", "[BufferTest]") 54 | { 55 | auto buf = Buffer(); 56 | char a[Buffer::BUF_DEFAULT_CAPACITY] { 0x05, 0x01 }; 57 | buf.copyFromBegin(a, Buffer::BUF_DEFAULT_CAPACITY); 58 | auto array = buf.duplicateDataToArray(); 59 | for (int i = 0; i < Buffer::BUF_DEFAULT_CAPACITY; ++i) { 60 | REQUIRE(a[i] == array[i]); 61 | } 62 | } 63 | 64 | TEST_CASE("CopyEvent", "[BufferTest]") 65 | { 66 | auto array = std::make_unique(2099); 67 | uvw::DataEvent event { std::move(array), 2099 }; 68 | auto buf = Buffer(); 69 | buf.copy(event); 70 | //like vector, when capacity is not enough, double capacity with data length. 71 | REQUIRE(*buf.getCapacityPtr() == event.length * 2); 72 | REQUIRE(buf.length() == 2099); 73 | //the capacity is enough, nothing happen. 74 | buf.copy(event); 75 | REQUIRE(*buf.getCapacityPtr() == event.length * 2); 76 | REQUIRE(buf.length() == 2099 * 2); 77 | event.length = 0; 78 | buf.copy(event); // no data to copy, because it's length is zero. 79 | REQUIRE(buf.length() == 2099 * 2); 80 | auto array2 = std::make_unique(2099); 81 | for (int i = 0; i < 2099; ++i) 82 | array2[i] = i % 255; 83 | uvw::DataEvent event2 { std::move(array2), 2099 }; 84 | REQUIRE(array2 == nullptr); 85 | buf.copyFromBegin(event2); 86 | REQUIRE(buf.length() == 2099); //when we copy copyFromBegin, the length is reset to event2 length. 87 | REQUIRE(*buf.getCapacityPtr() == event2.length * 2); 88 | for (int i = 0; i < 2099; ++i) { 89 | REQUIRE(buf[i] == event2.data[i]); 90 | } 91 | } 92 | 93 | TEST_CASE("UDPCopyEvent", "[BufferTest]") 94 | { 95 | auto array = std::make_unique(2099); 96 | uvw::Addr addr; //fake sender 97 | uvw::UDPDataEvent event { std::move(addr), std::move(array), 2099, false }; 98 | auto buf = Buffer(); 99 | buf.copy(event); 100 | //like vector, when capacity is not enough, double capacity with data length. 101 | REQUIRE(*buf.getCapacityPtr() == event.length * 2); 102 | REQUIRE(buf.length() == 2099); 103 | //the capacity is enough, nothing happen. 104 | buf.copy(event); 105 | REQUIRE(*buf.getCapacityPtr() == event.length * 2); 106 | REQUIRE(buf.length() == 2099 * 2); 107 | event.length = 0; 108 | buf.copy(event); // no data to copy, because it's length is zero. 109 | REQUIRE(buf.length() == 2099 * 2); 110 | } 111 | -------------------------------------------------------------------------------- /src/uvw/poll.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_POLL_INCLUDE_H 2 | #define UVW_POLL_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "handle.hpp" 9 | #include "util.h" 10 | 11 | 12 | namespace uvw { 13 | 14 | 15 | namespace details { 16 | 17 | 18 | enum class UVPollEvent: std::underlying_type_t { 19 | READABLE = UV_READABLE, 20 | WRITABLE = UV_WRITABLE, 21 | DISCONNECT = UV_DISCONNECT, 22 | PRIORITIZED = UV_PRIORITIZED 23 | }; 24 | 25 | 26 | } 27 | 28 | 29 | /** 30 | * @brief PollEvent event. 31 | * 32 | * It will be emitted by PollHandle according with its functionalities. 33 | */ 34 | struct PollEvent { 35 | explicit PollEvent(Flags events) noexcept; 36 | 37 | /** 38 | * @brief Detected events all in one. 39 | * 40 | * Available flags are: 41 | * 42 | * * `PollHandle::Event::READABLE` 43 | * * `PollHandle::Event::WRITABLE` 44 | * * `PollHandle::Event::DISCONNECT` 45 | * * `PollHandle::Event::PRIORITIZED` 46 | */ 47 | Flags flags; 48 | }; 49 | 50 | 51 | /** 52 | * @brief The PollHandle handle. 53 | * 54 | * Poll handles are used to watch file descriptors for readability, writability 55 | * and disconnection. 56 | * 57 | * To create a `PollHandle` through a `Loop`, arguments follow: 58 | * 59 | * * A descriptor that can be: 60 | * * either an `int` file descriptor 61 | * * or a `OSSocketHandle` socket descriptor 62 | * 63 | * See the official 64 | * [documentation](http://docs.libuv.org/en/v1.x/poll.html) 65 | * for further details. 66 | */ 67 | class PollHandle final: public Handle { 68 | static void startCallback(uv_poll_t *handle, int status, int events); 69 | 70 | public: 71 | using Event = details::UVPollEvent; 72 | 73 | explicit PollHandle(ConstructorAccess ca, std::shared_ptr ref, int desc); 74 | explicit PollHandle(ConstructorAccess ca, std::shared_ptr ref, OSSocketHandle sock); 75 | 76 | /** 77 | * @brief Initializes the handle. 78 | * @return True in case of success, false otherwise. 79 | */ 80 | bool init(); 81 | 82 | /** 83 | * @brief Starts polling the file descriptor. 84 | * 85 | * Available flags are: 86 | * 87 | * * `PollHandle::Event::READABLE` 88 | * * `PollHandle::Event::WRITABLE` 89 | * * `PollHandle::Event::DISCONNECT` 90 | * * `PollHandle::Event::PRIORITIZED` 91 | * 92 | * As soon as an event is detected, a PollEvent is emitted by the 93 | * handle.
94 | * It could happen that ErrorEvent events are emitted while running. 95 | * 96 | * Calling more than once this method will update the flags to which the 97 | * caller is interested. 98 | * 99 | * @param flags The events to which the caller is interested. 100 | */ 101 | void start(Flags flags); 102 | 103 | /** 104 | * @brief Starts polling the file descriptor. 105 | * 106 | * Available flags are: 107 | * 108 | * * `PollHandle::Event::READABLE` 109 | * * `PollHandle::Event::WRITABLE` 110 | * * `PollHandle::Event::DISCONNECT` 111 | * * `PollHandle::Event::PRIORITIZED` 112 | * 113 | * As soon as an event is detected, a PollEvent is emitted by the 114 | * handle.
115 | * It could happen that ErrorEvent events are emitted while running. 116 | * 117 | * Calling more than once this method will update the flags to which the 118 | * caller is interested. 119 | * 120 | * @param event The event to which the caller is interested. 121 | */ 122 | void start(Event event); 123 | 124 | /** 125 | * @brief Stops polling the file descriptor. 126 | */ 127 | void stop(); 128 | 129 | private: 130 | enum { FD, SOCKET } tag; 131 | union { 132 | int fd; 133 | OSSocketHandle::Type socket; 134 | }; 135 | }; 136 | 137 | 138 | } 139 | 140 | 141 | #ifndef UVW_AS_LIB 142 | #include "poll.cpp" 143 | #endif 144 | 145 | #endif // UVW_POLL_INCLUDE_H 146 | -------------------------------------------------------------------------------- /src/uvw/fs_event.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_FS_EVENT_INCLUDE_H 2 | #define UVW_FS_EVENT_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "handle.hpp" 9 | #include "util.h" 10 | #include "loop.h" 11 | 12 | 13 | namespace uvw { 14 | 15 | 16 | namespace details { 17 | 18 | 19 | enum class UVFsEventFlags: std::underlying_type_t { 20 | WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY, 21 | STAT = UV_FS_EVENT_STAT, 22 | RECURSIVE = UV_FS_EVENT_RECURSIVE 23 | }; 24 | 25 | 26 | enum class UVFsEvent: std::underlying_type_t { 27 | RENAME = UV_RENAME, 28 | CHANGE = UV_CHANGE 29 | }; 30 | 31 | 32 | } 33 | 34 | 35 | /** 36 | * @brief FsEventEvent event. 37 | * 38 | * It will be emitted by FsEventHandle according with its functionalities. 39 | */ 40 | struct FsEventEvent { 41 | FsEventEvent(const char * pathname, Flags events); 42 | 43 | /** 44 | * @brief The path to the file being monitored. 45 | * 46 | * If the handle was started with a directory, the filename parameter will 47 | * be a relative path to a file contained in the directory. 48 | */ 49 | const char * filename; 50 | 51 | /** 52 | * @brief Detected events all in one. 53 | * 54 | * Available flags are: 55 | * 56 | * * `FsEventHandle::Watch::RENAME` 57 | * * `FsEventHandle::Watch::CHANGE` 58 | */ 59 | Flags flags; 60 | }; 61 | 62 | 63 | /** 64 | * @brief The FsEventHandle handle. 65 | * 66 | * These handles allow the user to monitor a given path for changes, for 67 | * example, if the file was renamed or there was a generic change in it. The 68 | * best backend for the job on each platform is chosen by the handle. 69 | * 70 | * To create a `FsEventHandle` through a `Loop`, no arguments are required. 71 | * 72 | * See the official 73 | * [documentation](http://docs.libuv.org/en/v1.x/fs_event.html) 74 | * for further details. 75 | */ 76 | class FsEventHandle final: public Handle { 77 | static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status); 78 | 79 | public: 80 | using Watch = details::UVFsEvent; 81 | using Event = details::UVFsEventFlags; 82 | 83 | using Handle::Handle; 84 | 85 | /** 86 | * @brief Initializes the handle. 87 | * @return True in case of success, false otherwise. 88 | */ 89 | bool init(); 90 | 91 | /** 92 | * @brief Starts watching the specified path. 93 | * 94 | * It will watch the specified path for changes.
95 | * As soon as a change is observed, a FsEventEvent is emitted by the 96 | * handle.
97 | * It could happen that ErrorEvent events are emitted while running. 98 | * 99 | * Available flags are: 100 | * 101 | * * `FsEventHandle::Event::WATCH_ENTRY` 102 | * * `FsEventHandle::Event::STAT` 103 | * * `FsEventHandle::Event::RECURSIVE` 104 | * 105 | * @param path The file or directory to be monitored. 106 | * @param flags Additional flags to control the behavior. 107 | */ 108 | void start(std::string path, Flags flags = Flags{}); 109 | 110 | /** 111 | * @brief Starts watching the specified path. 112 | * 113 | * It will watch the specified path for changes.
114 | * As soon as a change is observed, a FsEventEvent is emitted by the 115 | * handle.
116 | * It could happen that ErrorEvent events are emitted while running. 117 | * 118 | * Available flags are: 119 | * 120 | * * `FsEventHandle::Event::WATCH_ENTRY` 121 | * * `FsEventHandle::Event::STAT` 122 | * * `FsEventHandle::Event::RECURSIVE` 123 | * 124 | * @param path The file or directory to be monitored. 125 | * @param flag Additional flag to control the behavior. 126 | */ 127 | void start(std::string path, Event flag); 128 | 129 | /** 130 | * @brief Stops polling the file descriptor. 131 | */ 132 | void stop(); 133 | 134 | /** 135 | * @brief Gets the path being monitored. 136 | * @return The path being monitored, an empty string in case of errors. 137 | */ 138 | std::string path() noexcept; 139 | }; 140 | 141 | 142 | } 143 | 144 | 145 | #ifndef UVW_AS_LIB 146 | #include "fs_event.cpp" 147 | #endif 148 | 149 | #endif // UVW_FS_EVENT_INCLUDE_H 150 | -------------------------------------------------------------------------------- /src/uvw/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TTY_INCLUDE_H 2 | #define UVW_TTY_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "stream.h" 9 | #include "util.h" 10 | 11 | 12 | namespace uvw { 13 | 14 | 15 | namespace details { 16 | 17 | 18 | struct ResetModeMemo { 19 | ~ResetModeMemo(); 20 | }; 21 | 22 | 23 | enum class UVTTYModeT: std::underlying_type_t { 24 | NORMAL = UV_TTY_MODE_NORMAL, 25 | RAW = UV_TTY_MODE_RAW, 26 | IO = UV_TTY_MODE_IO 27 | }; 28 | 29 | 30 | enum class UVTTYVTermStateT: std::underlying_type_t { 31 | SUPPORTED = UV_TTY_SUPPORTED, 32 | UNSUPPORTED = UV_TTY_UNSUPPORTED 33 | }; 34 | 35 | 36 | } 37 | 38 | 39 | /** 40 | * @brief The TTYHandle handle. 41 | * 42 | * TTY handles represent a stream for the console. 43 | * 44 | * To create a `TTYHandle` through a `Loop`, arguments follow: 45 | * 46 | * * A valid FileHandle. Usually the file descriptor will be: 47 | * * `uvw::StdIN` or `0` for `stdin` 48 | * * `uvw::StdOUT` or `1` for `stdout` 49 | * * `uvw::StdERR` or `2` for `stderr` 50 | * * A boolean value that specifies the plan on calling `read()` with this 51 | * stream. Remember that `stdin` is readable, `stdout` is not. 52 | * 53 | * See the official 54 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init) 55 | * for further details. 56 | */ 57 | class TTYHandle final: public StreamHandle { 58 | static std::shared_ptr resetModeMemo(); 59 | 60 | public: 61 | using Mode = details::UVTTYModeT; 62 | using VTermState = details::UVTTYVTermStateT; 63 | 64 | explicit TTYHandle(ConstructorAccess ca, std::shared_ptr ref, FileHandle desc, bool readable); 65 | 66 | /** 67 | * @brief Initializes the handle. 68 | * @return True in case of success, false otherwise. 69 | */ 70 | bool init(); 71 | 72 | /** 73 | * @brief Sets the TTY using the specified terminal mode. 74 | * 75 | * Available modes are: 76 | * 77 | * * `TTY::Mode::NORMAL` 78 | * * `TTY::Mode::RAW` 79 | * * `TTY::Mode::IO` 80 | * 81 | * See the official 82 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t) 83 | * for further details. 84 | * 85 | * @param m The mode to be set. 86 | * @return True in case of success, false otherwise. 87 | */ 88 | bool mode(Mode m); 89 | 90 | /** 91 | * @brief Resets TTY settings to default values. 92 | * @return True in case of success, false otherwise. 93 | */ 94 | bool reset() noexcept; 95 | 96 | /** 97 | * @brief Gets the current Window size. 98 | * @return The current Window size or `{-1, -1}` in case of errors. 99 | */ 100 | WinSize getWinSize(); 101 | 102 | /** 103 | * @brief Controls whether console virtual terminal sequences are processed 104 | * by the library or console. 105 | * 106 | * This function is only meaningful on Windows systems. On Unix it is 107 | * silently ignored. 108 | * 109 | * Available states are: 110 | * 111 | * * `TTY::VTermState::SUPPORTED` 112 | * * `TTY::VTermState::UNSUPPORTED` 113 | * 114 | * See the official 115 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) 116 | * for further details. 117 | * 118 | * @param s The state to be set. 119 | */ 120 | void vtermState(VTermState s) const noexcept; 121 | 122 | /** 123 | * @brief Gets the current state of whether console virtual terminal 124 | * sequences are handled by the library or the console. 125 | * 126 | * This function is not implemented on Unix. 127 | * 128 | * Available states are: 129 | * 130 | * * `TTY::VTermState::SUPPORTED` 131 | * * `TTY::VTermState::UNSUPPORTED` 132 | * 133 | * See the official 134 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) 135 | * for further details. 136 | * 137 | * @return The current state. 138 | */ 139 | VTermState vtermState() const noexcept; 140 | 141 | private: 142 | std::shared_ptr memo; 143 | FileHandle::Type fd; 144 | int rw; 145 | }; 146 | 147 | 148 | } 149 | 150 | 151 | #ifndef UVW_AS_LIB 152 | #include "tty.cpp" 153 | #endif 154 | 155 | #endif // UVW_TTY_INCLUDE_H 156 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: false 11 | AlignTrailingComments: false 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Empty 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: All 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: MultiLine 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: true 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: true 33 | AfterNamespace: true 34 | AfterObjCDeclaration: false 35 | AfterStruct: true 36 | AfterUnion: false 37 | AfterExternBlock: true 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: All 45 | BreakBeforeBraces: Custom 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeComma 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 0 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: false 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: false 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: false 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Preserve 70 | IncludeCategories: 71 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 75 | Priority: 3 76 | SortPriority: 0 77 | - Regex: '.*' 78 | Priority: 1 79 | SortPriority: 0 80 | IncludeIsMainRegex: '(Test)?$' 81 | IncludeIsMainSourceRegex: '' 82 | IndentCaseLabels: false 83 | IndentGotoLabels: true 84 | IndentPPDirectives: None 85 | IndentWidth: 4 86 | IndentWrappedFunctionNames: false 87 | JavaScriptQuotes: Leave 88 | JavaScriptWrapImports: true 89 | KeepEmptyLinesAtTheStartOfBlocks: true 90 | MacroBlockBegin: '' 91 | MacroBlockEnd: '' 92 | MaxEmptyLinesToKeep: 1 93 | NamespaceIndentation: Inner 94 | ObjCBinPackProtocolList: Auto 95 | ObjCBlockIndentWidth: 4 96 | ObjCSpaceAfterProperty: true 97 | ObjCSpaceBeforeProtocolList: true 98 | PenaltyBreakAssignment: 2 99 | PenaltyBreakBeforeFirstCallParameter: 19 100 | PenaltyBreakComment: 300 101 | PenaltyBreakFirstLessLess: 120 102 | PenaltyBreakString: 1000 103 | PenaltyBreakTemplateDeclaration: 10 104 | PenaltyExcessCharacter: 1000000 105 | PenaltyReturnTypeOnItsOwnLine: 60 106 | PointerAlignment: Left 107 | ReflowComments: true 108 | SortIncludes: true 109 | SortUsingDeclarations: true 110 | SpaceAfterCStyleCast: false 111 | SpaceAfterLogicalNot: false 112 | SpaceAfterTemplateKeyword: true 113 | SpaceBeforeAssignmentOperators: true 114 | SpaceBeforeCpp11BracedList: true 115 | SpaceBeforeCtorInitializerColon: true 116 | SpaceBeforeInheritanceColon: true 117 | SpaceBeforeParens: ControlStatements 118 | SpaceBeforeRangeBasedForLoopColon: true 119 | SpaceInEmptyBlock: true 120 | SpaceInEmptyParentheses: false 121 | SpacesBeforeTrailingComments: 1 122 | SpacesInAngles: false 123 | SpacesInConditionalStatement: false 124 | SpacesInContainerLiterals: true 125 | SpacesInCStyleCastParentheses: false 126 | SpacesInParentheses: false 127 | SpacesInSquareBrackets: false 128 | SpaceBeforeSquareBrackets: false 129 | Standard: Latest 130 | StatementMacros: 131 | - Q_UNUSED 132 | - QT_REQUIRE_VERSION 133 | TabWidth: 4 134 | UseCRLF: false 135 | UseTab: Never 136 | ... 137 | 138 | -------------------------------------------------------------------------------- /src/ssrutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssrutils.h - Misc utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the shadowsocks-libev. 7 | * 8 | * shadowsocks-libev is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * shadowsocks-libev is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with shadowsocks-libev; see the file COPYING. If not, see 20 | * . 21 | */ 22 | #ifndef _SSR_UTILS_H 23 | #define _SSR_UTILS_H 24 | 25 | #if defined(USE_CRYPTO_OPENSSL) 26 | 27 | #include 28 | #define USING_CRYPTO OPENSSL_VERSION_TEXT 29 | 30 | #elif defined(USE_CRYPTO_POLARSSL) 31 | #include 32 | #define USING_CRYPTO POLARSSL_VERSION_STRING_FULL 33 | 34 | #elif defined(USE_CRYPTO_MBEDTLS) 35 | #include 36 | #define USING_CRYPTO MBEDTLS_VERSION_STRING_FULL 37 | 38 | #endif 39 | 40 | #ifdef __cplusplus 41 | extern "C" 42 | { 43 | #endif 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | struct tm* ssr_safe_localtime(time_t* t, struct tm* tp); 51 | #ifdef ANDROID 52 | 53 | #include 54 | 55 | #define USE_TTY() 56 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "shadowsocks", __VA_ARGS__)) 57 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "shadowsocks", __VA_ARGS__)) 58 | 59 | #else // ANDROID 60 | void ssr_log_print(const char* fmt,...); 61 | extern int use_tty; 62 | #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" 63 | #define LOGI(format, ...) \ 64 | do { \ 65 | time_t now = time(NULL); \ 66 | struct tm tp; \ 67 | char timestr[20]; \ 68 | strftime(timestr, 20, TIME_FORMAT, ssr_safe_localtime(&now, &tp)); \ 69 | if (use_tty) { \ 70 | ssr_log_print("\e[01;32m %s INFO: \e[0m" format, timestr, ##__VA_ARGS__); \ 71 | } else { \ 72 | ssr_log_print(" %s INFO: " format , timestr, ##__VA_ARGS__); \ 73 | } \ 74 | } while (0) 75 | 76 | #define LOGE(format, ...) \ 77 | do { \ 78 | time_t now = time(NULL); \ 79 | struct tm tp; \ 80 | char timestr[20]; \ 81 | strftime(timestr, 20, TIME_FORMAT, ssr_safe_localtime(&now, &tp)); \ 82 | if (use_tty) { \ 83 | ssr_log_print( "\e[01;35m %s ERROR: \e[0m" format, timestr, ##__VA_ARGS__); \ 84 | } else { \ 85 | ssr_log_print( " %s ERROR: " format , timestr, ##__VA_ARGS__); \ 86 | } \ 87 | } while (0) 88 | #if defined(_WIN32) 89 | #define USE_TTY() 90 | #else 91 | #define USE_TTY() \ 92 | do { \ 93 | use_tty = isatty(STDERR_FILENO); \ 94 | } while (0) 95 | #endif 96 | #endif // ANDROID 97 | 98 | void FATAL(const char* msg); 99 | 100 | void* ss_malloc(size_t size); 101 | void* ss_realloc(void* ptr, size_t new_size); 102 | 103 | #define ss_free(ptr) \ 104 | do { \ 105 | free(ptr); \ 106 | ptr = NULL; \ 107 | } while (0) 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | #endif // _UTILS_H 113 | -------------------------------------------------------------------------------- /src/obfs/base64.c: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | 3 | /* BASE 64 encode table */ 4 | static const char base64en[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 5 | 6 | #define BASE64_PAD '=' 7 | 8 | #define BASE64DE_FIRST '+' 9 | #define BASE64DE_LAST 'z' 10 | 11 | /* ASCII order for BASE 64 decode, -1 in unused character */ 12 | static const signed char base64de[] = { 13 | -1, 14 | -1, 15 | -1, 16 | -1, 17 | -1, 18 | -1, 19 | -1, 20 | -1, 21 | -1, 22 | -1, 23 | -1, 24 | -1, 25 | -1, 26 | -1, 27 | -1, 28 | -1, 29 | -1, 30 | -1, 31 | -1, 32 | -1, 33 | -1, 34 | -1, 35 | -1, 36 | -1, 37 | -1, 38 | -1, 39 | -1, 40 | -1, 41 | -1, 42 | -1, 43 | -1, 44 | -1, 45 | -1, 46 | -1, 47 | -1, 48 | -1, 49 | -1, 50 | -1, 51 | -1, 52 | -1, 53 | /* '+', ',', '-', '.', '/', */ 54 | -1, 55 | -1, 56 | -1, 57 | 62, 58 | -1, 59 | -1, 60 | -1, 61 | 63, 62 | /* '0', '1', '2', '3', '4', '5', '6', '7', */ 63 | 52, 64 | 53, 65 | 54, 66 | 55, 67 | 56, 68 | 57, 69 | 58, 70 | 59, 71 | /* '8', '9', ':', ';', '<', '=', '>', '?', */ 72 | 60, 73 | 61, 74 | -1, 75 | -1, 76 | -1, 77 | -1, 78 | -1, 79 | -1, 80 | /* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ 81 | -1, 82 | 0, 83 | 1, 84 | 2, 85 | 3, 86 | 4, 87 | 5, 88 | 6, 89 | /* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ 90 | 7, 91 | 8, 92 | 9, 93 | 10, 94 | 11, 95 | 12, 96 | 13, 97 | 14, 98 | /* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ 99 | 15, 100 | 16, 101 | 17, 102 | 18, 103 | 19, 104 | 20, 105 | 21, 106 | 22, 107 | /* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ 108 | 23, 109 | 24, 110 | 25, 111 | -1, 112 | -1, 113 | -1, 114 | -1, 115 | -1, 116 | /* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ 117 | -1, 118 | 26, 119 | 27, 120 | 28, 121 | 29, 122 | 30, 123 | 31, 124 | 32, 125 | /* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ 126 | 33, 127 | 34, 128 | 35, 129 | 36, 130 | 37, 131 | 38, 132 | 39, 133 | 40, 134 | /* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ 135 | 41, 136 | 42, 137 | 43, 138 | 44, 139 | 45, 140 | 46, 141 | 47, 142 | 48, 143 | /* 'x', 'y', 'z', */ 144 | 49, 145 | 50, 146 | 51, 147 | }; 148 | 149 | int base64_encode(const unsigned char* in, unsigned int inlen, char* out) 150 | { 151 | unsigned int i, j; 152 | 153 | for (i = j = 0; i < inlen; i++) { 154 | int s = i % 3; /* from 6/gcd(6, 8) */ 155 | 156 | switch (s) { 157 | case 0: 158 | out[j++] = base64en[(in[i] >> 2) & 0x3F]; 159 | continue; 160 | case 1: 161 | out[j++] = base64en[((in[i - 1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)]; 162 | continue; 163 | case 2: 164 | out[j++] = base64en[((in[i - 1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)]; 165 | out[j++] = base64en[in[i] & 0x3F]; 166 | } 167 | } 168 | 169 | /* move back */ 170 | i -= 1; 171 | 172 | /* check the last and add padding */ 173 | if ((i % 3) == 0) { 174 | out[j++] = base64en[(in[i] & 0x3) << 4]; 175 | out[j++] = BASE64_PAD; 176 | out[j++] = BASE64_PAD; 177 | } else if ((i % 3) == 1) { 178 | out[j++] = base64en[(in[i] & 0xF) << 2]; 179 | out[j++] = BASE64_PAD; 180 | } 181 | 182 | return BASE64_OK; 183 | } 184 | 185 | int base64_decode(const char* in, unsigned int inlen, unsigned char* out) 186 | { 187 | unsigned int i, j; 188 | 189 | for (i = j = 0; i < inlen; i++) { 190 | int c; 191 | int s = i % 4; /* from 8/gcd(6, 8) */ 192 | 193 | if (in[i] == '=') 194 | return BASE64_OK; 195 | 196 | if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST || (c = base64de[(int)in[i]]) == -1) 197 | return BASE64_INVALID; 198 | 199 | switch (s) { 200 | case 0: 201 | out[j] = ((unsigned int)c << 2) & 0xFF; 202 | continue; 203 | case 1: 204 | out[j++] += ((unsigned int)c >> 4) & 0x3; 205 | 206 | /* if not last char with padding */ 207 | if (i < (inlen - 3) || in[inlen - 2] != '=') 208 | out[j] = (unsigned char)(((unsigned int)c & 0xF) << 4); 209 | continue; 210 | case 2: 211 | out[j++] += ((unsigned int)c >> 2) & 0xF; 212 | 213 | /* if not last char with padding */ 214 | if (i < (inlen - 2) || in[inlen - 1] != '=') 215 | out[j] = (unsigned char)(((unsigned int)c & 0x3) << 6); 216 | continue; 217 | case 3: 218 | out[j++] += (unsigned char)c; 219 | } 220 | } 221 | 222 | return BASE64_OK; 223 | } 224 | -------------------------------------------------------------------------------- /cmake/FindLibUV.cmake: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | FindLibUV 3 | --------- 4 | 5 | Find libuv includes and library. 6 | 7 | Imported Targets 8 | ^^^^^^^^^^^^^^^^ 9 | 10 | An :ref:`imported target ` named 11 | ``LibUV::LibUV`` is provided if libuv has been found. 12 | 13 | Result Variables 14 | ^^^^^^^^^^^^^^^^ 15 | 16 | This module defines the following variables: 17 | 18 | ``LibUV_FOUND`` 19 | True if libuv was found, false otherwise. 20 | ``LibUV_INCLUDE_DIRS`` 21 | Include directories needed to include libuv headers. 22 | ``LibUV_LIBRARIES`` 23 | Libraries needed to link to libuv. 24 | ``LibUV_VERSION`` 25 | The version of libuv found. 26 | ``LibUV_VERSION_MAJOR`` 27 | The major version of libuv. 28 | ``LibUV_VERSION_MINOR`` 29 | The minor version of libuv. 30 | ``LibUV_VERSION_PATCH`` 31 | The patch version of libuv. 32 | 33 | Cache Variables 34 | ^^^^^^^^^^^^^^^ 35 | 36 | This module uses the following cache variables: 37 | 38 | ``LibUV_LIBRARY`` 39 | The location of the libuv library file. 40 | ``LibUV_INCLUDE_DIR`` 41 | The location of the libuv include directory containing ``uv.h``. 42 | 43 | The cache variables should not be used by project code. 44 | They may be set by end users to point at libuv components. 45 | #]=======================================================================] 46 | 47 | #============================================================================= 48 | # Copyright 2014-2016 Kitware, Inc. 49 | # 50 | # Distributed under the OSI-approved BSD License (the "License"); 51 | # see accompanying file Copyright.txt for details. 52 | # 53 | # This software is distributed WITHOUT ANY WARRANTY; without even the 54 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 55 | # See the License for more information. 56 | #============================================================================= 57 | # (To distribute this file outside of CMake, substitute the full 58 | # License text for the above reference.) 59 | 60 | #----------------------------------------------------------------------------- 61 | if(STATIC_LINK_LIBUV) 62 | find_library(LibUV_LIBRARY 63 | NAMES libuv.a 64 | ) 65 | else() 66 | find_library(LibUV_LIBRARY 67 | NAMES uv 68 | ) 69 | endif() 70 | mark_as_advanced(LibUV_LIBRARY) 71 | 72 | find_path(LibUV_INCLUDE_DIR 73 | NAMES uv.h 74 | ) 75 | mark_as_advanced(LibUV_INCLUDE_DIR) 76 | 77 | #----------------------------------------------------------------------------- 78 | # Extract version number if possible. 79 | set(_LibUV_H_REGEX "#[ \t]*define[ \t]+UV_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+") 80 | if(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv-version.h") 81 | file(STRINGS "${LibUV_INCLUDE_DIR}/uv-version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") 82 | elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv.h") 83 | file(STRINGS "${LibUV_INCLUDE_DIR}/uv.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") 84 | else() 85 | set(_LibUV_H "") 86 | endif() 87 | foreach(c MAJOR MINOR PATCH) 88 | if(_LibUV_H MATCHES "#[ \t]*define[ \t]+UV_VERSION_${c}[ \t]+([0-9]+)") 89 | set(_LibUV_VERSION_${c} "${CMAKE_MATCH_1}") 90 | else() 91 | unset(_LibUV_VERSION_${c}) 92 | endif() 93 | endforeach() 94 | if(DEFINED _LibUV_VERSION_MAJOR AND DEFINED _LibUV_VERSION_MINOR) 95 | set(LibUV_VERSION_MAJOR "${_LibUV_VERSION_MAJOR}") 96 | set(LibUV_VERSION_MINOR "${_LibUV_VERSION_MINOR}") 97 | set(LibUV_VERSION "${LibUV_VERSION_MAJOR}.${LibUV_VERSION_MINOR}") 98 | if(DEFINED _LibUV_VERSION_PATCH) 99 | set(LibUV_VERSION_PATCH "${_LibUV_VERSION_PATCH}") 100 | set(LibUV_VERSION "${LibUV_VERSION}.${LibUV_VERSION_PATCH}") 101 | else() 102 | unset(LibUV_VERSION_PATCH) 103 | endif() 104 | else() 105 | set(LibUV_VERSION_MAJOR "") 106 | set(LibUV_VERSION_MINOR "") 107 | set(LibUV_VERSION_PATCH "") 108 | set(LibUV_VERSION "") 109 | endif() 110 | unset(_LibUV_VERSION_MAJOR) 111 | unset(_LibUV_VERSION_MINOR) 112 | unset(_LibUV_VERSION_PATCH) 113 | unset(_LibUV_H_REGEX) 114 | unset(_LibUV_H) 115 | 116 | #----------------------------------------------------------------------------- 117 | include(FindPackageHandleStandardArgs) 118 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUV 119 | FOUND_VAR LibUV_FOUND 120 | REQUIRED_VARS LibUV_LIBRARY LibUV_INCLUDE_DIR 121 | VERSION_VAR LibUV_VERSION 122 | ) 123 | set(LIBUV_FOUND ${LibUV_FOUND}) 124 | 125 | #----------------------------------------------------------------------------- 126 | # Provide documented result variables and targets. 127 | if(LibUV_FOUND) 128 | set(LibUV_INCLUDE_DIRS ${LibUV_INCLUDE_DIR}) 129 | set(LibUV_LIBRARIES ${LibUV_LIBRARY}) 130 | message("libuv library:" ${LibUV_LIBRARY}) 131 | if(NOT TARGET LibUV::LibUV) 132 | add_library(LibUV::LibUV UNKNOWN IMPORTED) 133 | set_target_properties(LibUV::LibUV PROPERTIES 134 | IMPORTED_LOCATION "${LibUV_LIBRARY}" 135 | INTERFACE_INCLUDE_DIRECTORIES "${LibUV_INCLUDE_DIRS}" 136 | ) 137 | endif() 138 | endif() 139 | 140 | -------------------------------------------------------------------------------- /src/ConnectionContext.cpp: -------------------------------------------------------------------------------- 1 | #include "ConnectionContext.hpp" 2 | 3 | #include "Buffer.hpp" 4 | #include "LogHelper.h" 5 | #include "ObfsClass.hpp" 6 | #include "uvw/tcp.h" 7 | namespace 8 | { 9 | void dummyDisposeObfs(obfs*) 10 | { 11 | } 12 | void dummyDisposeEncCtx(struct enc_ctx*) 13 | { 14 | } 15 | 16 | } // namespace 17 | 18 | ConnectionContext::ConnectionContext(std::shared_ptr tcpHandle, ObfsClass* obfsClassPtr, CipherEnv* cipherEnvPtr) 19 | : obfsClassPtr(obfsClassPtr) 20 | , cipherEnvPtr(cipherEnvPtr) 21 | , localBuf { new Buffer } 22 | , protocolPtr { nullptr, obfsClassPtr->protocol_plugin == nullptr ? dummyDisposeObfs : obfsClassPtr->protocol_plugin->dispose } 23 | , obfsPtr { nullptr, obfsClassPtr->obfs_plugin == nullptr ? dummyDisposeObfs : obfsClassPtr->obfs_plugin->dispose } 24 | , e_ctx { nullptr, dummyDisposeEncCtx } 25 | , d_ctx { nullptr, dummyDisposeEncCtx } 26 | , client(std::move(tcpHandle)) 27 | { 28 | } 29 | 30 | ConnectionContext::ConnectionContext() 31 | : localBuf {} 32 | , protocolPtr { nullptr, dummyDisposeObfs } 33 | , obfsPtr { nullptr, dummyDisposeObfs } 34 | , e_ctx { nullptr, dummyDisposeEncCtx } 35 | , d_ctx { 36 | nullptr, dummyDisposeEncCtx 37 | } 38 | { 39 | } 40 | 41 | ConnectionContext::ConnectionContext(ConnectionContext&& that) noexcept 42 | : obfsClassPtr(that.obfsClassPtr) 43 | , cipherEnvPtr(that.cipherEnvPtr) 44 | , localBuf { std::move(that.localBuf) } 45 | , remoteBuf { std::move(that.remoteBuf) } 46 | , protocolPtr { std::move(that.protocolPtr) } 47 | , obfsPtr { std::move(that.obfsPtr) } 48 | , e_ctx { std::move(that.e_ctx) } 49 | , d_ctx { std::move( 50 | that.d_ctx) } 51 | , client(std::move(that.client)) 52 | , remote(std::move(that.remote)) 53 | { 54 | } 55 | 56 | ConnectionContext& ConnectionContext::operator=(ConnectionContext&& that) noexcept 57 | { 58 | 59 | localBuf = std::move(that.localBuf); 60 | remoteBuf = std::move(that.remoteBuf); 61 | protocolPtr = std::move(that.protocolPtr); 62 | obfsPtr = std::move(that.obfsPtr); 63 | e_ctx = std::move(that.e_ctx); 64 | d_ctx = std::move(that.d_ctx); 65 | client = std::move(that.client); 66 | remote = std::move(that.remote); 67 | obfsClassPtr = that.obfsClassPtr; 68 | cipherEnvPtr = that.cipherEnvPtr; 69 | return *this; 70 | } 71 | 72 | void ConnectionContext::setRemoteTcpHandle(std::shared_ptr tcp) 73 | { 74 | remote = std::move(tcp); 75 | } 76 | 77 | server_info_t ConnectionContext::construct_obfs(CipherEnv& cipherEnv, ObfsClass& obfsClass, const profile_t& profile, int server_info_head_len) 78 | { 79 | server_info_t _server_info; 80 | memset(&_server_info, 0, sizeof(server_info_t)); 81 | if (cipherEnv.cipher.enc_method > TABLE) { 82 | auto encCtxRelease = [this](struct enc_ctx* p) { 83 | if (p == nullptr) 84 | return; 85 | enc_ctx_release(&this->cipherEnvPtr->cipher, p); 86 | free(p); 87 | }; 88 | e_ctx = { reinterpret_cast(malloc(sizeof(struct enc_ctx))), encCtxRelease }; 89 | d_ctx = { reinterpret_cast(malloc(sizeof(struct enc_ctx))), encCtxRelease }; 90 | enc_ctx_init(&cipherEnv.cipher, e_ctx.get(), 1); 91 | enc_ctx_init(&cipherEnv.cipher, d_ctx.get(), 0); 92 | } 93 | if (profile.remote_host) 94 | strcpy(_server_info.host, profile.remote_host); 95 | _server_info.port = profile.remote_port; 96 | _server_info.param = profile.obfs_param; 97 | _server_info.g_data = obfsClass.obfs_global; 98 | _server_info.head_len = server_info_head_len; 99 | _server_info.iv_len = enc_get_iv_len(&cipherEnv.cipher); 100 | _server_info.iv = e_ctx->evp.iv; 101 | _server_info.key = enc_get_key(&cipherEnv.cipher); 102 | _server_info.key_len = enc_get_key_len(&cipherEnv.cipher); 103 | _server_info.tcp_mss = 1452; 104 | _server_info.buffer_size = 2048; 105 | _server_info.cipher_env = &cipherEnv.cipher; 106 | 107 | if (obfsClass.obfs_plugin) { 108 | this->obfsPtr.reset(obfsClass.obfs_plugin->new_obfs()); 109 | obfsClass.obfs_plugin->set_server_info(obfsPtr.get(), &_server_info); 110 | } 111 | 112 | _server_info.param = profile.protocol_param; 113 | _server_info.g_data = obfsClass.protocol_global; 114 | 115 | if (obfsClass.protocol_plugin) { 116 | protocolPtr.reset(obfsClass.protocol_plugin->new_obfs()); 117 | _server_info.overhead = obfsClass.protocol_plugin->get_overhead(protocolPtr.get()) + (obfsClass.obfs_plugin ? obfsClass.obfs_plugin->get_overhead(obfsPtr.get()) : 0); 118 | obfsClass.protocol_plugin->set_server_info(protocolPtr.get(), &_server_info); 119 | } 120 | return _server_info; 121 | } 122 | 123 | ConnectionContext::~ConnectionContext() 124 | { 125 | if (remote) { 126 | remote->clear(); 127 | remote->close(); 128 | } 129 | if (client) { 130 | client->clear(); 131 | client->close(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(CMAKE_CXX_STANDARD 17) 3 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 4 | 5 | if (WIN32) 6 | set(WINSOCK2 ws2_32) 7 | set(CRYPT32 crypt32) 8 | elseif (NOT APPLE) 9 | find_library(LIBRT rt) 10 | endif () 11 | 12 | 13 | set(USE_CRYPTO_OPENSSL 1) 14 | 15 | set(SOURCE_FILES_LOCAL 16 | uvw/async.cpp 17 | uvw/check.cpp 18 | uvw/dns.cpp 19 | uvw/emitter.cpp 20 | uvw/fs.cpp 21 | uvw/fs_event.cpp 22 | uvw/fs_poll.cpp 23 | uvw/idle.cpp 24 | uvw/lib.cpp 25 | uvw/loop.cpp 26 | uvw/pipe.cpp 27 | uvw/poll.cpp 28 | uvw/prepare.cpp 29 | uvw/process.cpp 30 | uvw/signal.cpp 31 | uvw/stream.cpp 32 | uvw/tcp.cpp 33 | uvw/thread.cpp 34 | uvw/timer.cpp 35 | uvw/tty.cpp 36 | uvw/util.cpp 37 | uvw/work.cpp 38 | uvw/udp.cpp 39 | ssrutils.h 40 | obfs/crc32.h 41 | obfs/auth.c 42 | obfs/auth.h 43 | obfs/obfs.c 44 | obfs/obfs.h 45 | obfs/base64.h 46 | obfs/auth_chain.h 47 | obfs/auth_chain.c 48 | obfs/http_simple.h 49 | obfs/obfsutil.c 50 | obfs/base64.c 51 | obfs/tls1.2_ticket.h 52 | obfs/http_simple.c 53 | obfs/tls1.2_ticket.c 54 | obfs/crc32.c 55 | obfs/obfsutil.h 56 | ObfsClass.hpp 57 | ObfsClass.cpp 58 | Buffer.hpp 59 | encrypt.c 60 | ConnectionContext.hpp 61 | sockaddr_universal.h 62 | uvw_single.hpp 63 | ConnectionContext.cpp 64 | encrypt.h 65 | cache.h 66 | ssrutils.c 67 | shadowsocksr.h 68 | CipherEnv.hpp 69 | sockaddr_universal.c 70 | CipherEnv.cpp 71 | uthash.h 72 | Buffer.cpp 73 | cache.c 74 | NetUtils.hpp 75 | NetUtils.cpp 76 | TCPRelay.hpp 77 | UDPConnectionContext.cpp UDPConnectionContext.hpp UDPRelay.cpp UDPRelay.hpp) 78 | add_library(shadowsocksr-uvw-common OBJECT ${SOURCE_FILES_LOCAL}) 79 | target_compile_definitions(shadowsocksr-uvw-common PUBLIC UVW_AS_LIB) 80 | if (SSR_UVW_WITH_QT) 81 | if(NOT QV_QT_LIBNAME) 82 | set(QV_QT_LIBNAME Qt5) 83 | endif() 84 | message("find ${QV_QT_LIBNAME}") 85 | find_package(${QV_QT_LIBNAME} COMPONENTS Core REQUIRED) 86 | function(_qt_wrap_cpp outfiles) 87 | if(QV_QT_LIBNAME STREQUAL "Qt5") 88 | qt5_wrap_cpp(${outfiles} ${ARGN}) 89 | else() 90 | qt6_wrap_cpp(${outfiles} ${ARGN}) 91 | endif() 92 | set(${outfiles} ${${outfiles}} PARENT_SCOPE) 93 | endfunction() 94 | _qt_wrap_cpp(ssr_thread_moc SSRThread.hpp) 95 | set(SOURCE_FILES_LOCAL_QT 96 | ${ssr_thread_moc} 97 | SSRThread.cpp 98 | qt_ui_log.cpp 99 | ssr_log_utils.cpp 100 | local_uv.cpp 101 | #local_uv.cpp uses macro SSR_UVW_WITH_QT,so it's not part of shadowsocksr-uvw-common 102 | ) 103 | add_library(${PROJECT_NAME}-qt STATIC ${SOURCE_FILES_LOCAL_QT} $) 104 | target_compile_definitions(${PROJECT_NAME}-qt PUBLIC SSR_UVW_WITH_QT UVW_AS_LIB) 105 | set_target_properties(${PROJECT_NAME}-qt PROPERTIES POSITION_INDEPENDENT_CODE 1) 106 | add_library(shadowsocksr::uvw::qt ALIAS ${PROJECT_NAME}-qt) 107 | endif () 108 | include_directories(${LibUV_INCLUDE_DIR}) 109 | include_directories(${libsodium_include_dirs}) 110 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 111 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 112 | add_library(${PROJECT_NAME} STATIC local_uv.cpp ssr_log_utils.cpp $) 113 | #local_uv.cpp uses macro SSR_UVW_WITH_QT,so it's not part of shadowsocksr-uvw-common 114 | add_library(shadowsocksr::uvw ALIAS ${PROJECT_NAME}) 115 | set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE 1) 116 | target_compile_definitions(${PROJECT_NAME} PUBLIC UVW_AS_LIB) 117 | set( 118 | COMMON_LINK_LIBS 119 | ${LIBRT} 120 | ${LibUV_LIBRARIES} 121 | ${WINSOCK2} 122 | ${CRYPT32} 123 | ) 124 | 125 | set(ssr_crypto 126 | ${LIBCRYPTO} 127 | ${sodium_LIBRARIES} 128 | ) 129 | 130 | if(WIN32) 131 | target_link_libraries(shadowsocksr-uvw-common 132 | ${COMMON_LINK_LIBS} ${ssr_crypto}) 133 | endif() 134 | 135 | if (SSR_UVW_WITH_QT) 136 | target_link_libraries(${PROJECT_NAME}-qt ${QV_QT_LIBNAME}::Core 137 | ${COMMON_LINK_LIBS} ${ssr_crypto} 138 | ) 139 | endif () 140 | target_include_directories( 141 | ${PROJECT_NAME} 142 | PUBLIC 143 | $ 144 | ) 145 | 146 | target_link_libraries(${PROJECT_NAME} 147 | ${COMMON_LINK_LIBS} ${ssr_crypto} 148 | ) 149 | if(NOT WIN32) 150 | set(SSR_LOCAL_SOURCE ssr_local.cpp ssr_log_utils.cpp) 151 | else() 152 | set(SSR_LOCAL_SOURCE ssr_local.cpp win/getopt.c ssr_log_utils.cpp) 153 | endif() 154 | add_executable(ssr-local ${SSR_LOCAL_SOURCE}) 155 | target_compile_definitions(ssr-local PUBLIC UVW_AS_LIB) 156 | target_link_libraries(ssr-local shadowsocksr::uvw) 157 | install(TARGETS ssr-local RUNTIME DESTINATION bin) 158 | -------------------------------------------------------------------------------- /src/uvw/pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_PIPE_INCLUDE_H 2 | #define UVW_PIPE_INCLUDE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "request.hpp" 10 | #include "stream.h" 11 | #include "util.h" 12 | #include "loop.h" 13 | 14 | 15 | namespace uvw { 16 | 17 | 18 | namespace details { 19 | 20 | 21 | enum class UVChmodFlags: std::underlying_type_t { 22 | READABLE = UV_READABLE, 23 | WRITABLE = UV_WRITABLE 24 | }; 25 | 26 | 27 | } 28 | 29 | 30 | /** 31 | * @brief The PipeHandle handle. 32 | * 33 | * Pipe handles provide an abstraction over local domain sockets on Unix and 34 | * named pipes on Windows. 35 | * 36 | * To create a `PipeHandle` through a `Loop`, arguments follow: 37 | * 38 | * * An optional boolean value that indicates if this pipe will be used for 39 | * handle passing between processes. 40 | */ 41 | class PipeHandle final: public StreamHandle { 42 | public: 43 | using Chmod = details::UVChmodFlags; 44 | 45 | explicit PipeHandle(ConstructorAccess ca, std::shared_ptr ref, bool pass = false); 46 | 47 | /** 48 | * @brief Initializes the handle. 49 | * @return True in case of success, false otherwise. 50 | */ 51 | bool init(); 52 | 53 | /** 54 | * @brief Opens an existing file descriptor or HANDLE as a pipe. 55 | * 56 | * The passed file descriptor or HANDLE is not checked for its type, but 57 | * it’s required that it represents a valid pipe.
58 | * An ErrorEvent event is emitted in case of errors. 59 | * 60 | * @param file A valid file handle (either a file descriptor or a HANDLE). 61 | */ 62 | void open(FileHandle file); 63 | 64 | /** 65 | * @brief bind Binds the pipe to a file path (Unix) or a name (Windows). 66 | * 67 | * Paths on Unix get truncated typically between 92 and 108 bytes.
68 | * An ErrorEvent event is emitted in case of errors. 69 | * 70 | * @param name A valid file path. 71 | */ 72 | void bind(std::string name); 73 | 74 | /** 75 | * @brief Connects to the Unix domain socket or the named pipe. 76 | * 77 | * Paths on Unix get truncated typically between 92 and 108 bytes.
78 | * A ConnectEvent event is emitted when the connection has been 79 | * established.
80 | * An ErrorEvent event is emitted in case of errors during the connection. 81 | * 82 | * @param name A valid domain socket or named pipe. 83 | */ 84 | void connect(std::string name); 85 | 86 | /** 87 | * @brief Gets the name of the Unix domain socket or the named pipe. 88 | * @return The name of the Unix domain socket or the named pipe, an empty 89 | * string in case of errors. 90 | */ 91 | std::string sock() const noexcept; 92 | 93 | /** 94 | * @brief Gets the name of the Unix domain socket or the named pipe to which 95 | * the handle is connected. 96 | * @return The name of the Unix domain socket or the named pipe to which 97 | * the handle is connected, an empty string in case of errors. 98 | */ 99 | std::string peer() const noexcept; 100 | 101 | /** 102 | * @brief Sets the number of pending pipe this instance can handle. 103 | * 104 | * This method can be used to set the number of pending pipe this instance 105 | * handles when the pipe server is waiting for connections.
106 | * Note that this setting applies to Windows only. 107 | * 108 | * @param count The number of accepted pending pipe. 109 | */ 110 | void pending(int count) noexcept; 111 | 112 | /** 113 | * @brief Gets the number of pending pipe this instance can handle. 114 | * @return The number of pending pipe this instance can handle. 115 | */ 116 | int pending() noexcept; 117 | 118 | /** 119 | * @brief Used to receive handles over IPC pipes. 120 | * 121 | * Steps to be done: 122 | * 123 | * * Call `pending()`, if it’s greater than zero then proceed. 124 | * * Initialize a handle of the given type, as returned by `receive()`. 125 | * * Call `accept(pipe, handle)`. 126 | * 127 | * @return The type of the pending handle. Possible values are: 128 | * 129 | * * `HandleType::PIPE` 130 | * * `HandleType::TCP` 131 | * * `HandleType::UDP` 132 | * * `HandleType::UNKNOWN` 133 | */ 134 | HandleType receive() noexcept; 135 | 136 | /** 137 | * @brief Alters pipe permissions. 138 | * 139 | * It allows the pipe to be accessed from processes run by different users. 140 | * 141 | * Available flags are: 142 | * 143 | * * `PipeHandle::Chmod::READABLE` 144 | * * `PipeHandle::Chmod::WRITABLE` 145 | * 146 | * See the official 147 | * [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod) 148 | * for further details. 149 | * 150 | * @param flags A valid set of flags. 151 | * @return True in case of success, false otherwise. 152 | */ 153 | bool chmod(Flags flags) noexcept; 154 | 155 | private: 156 | bool ipc; 157 | }; 158 | 159 | 160 | } 161 | 162 | 163 | #ifndef UVW_AS_LIB 164 | #include "pipe.cpp" 165 | #endif 166 | 167 | #endif // UVW_PIPE_INCLUDE_H 168 | -------------------------------------------------------------------------------- /test/src/TestNetUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "NetUtils.hpp" 2 | #include "uvw/loop.h" 3 | #define CATCH_CONFIG_MAIN 4 | #include "catch.hpp" 5 | #include 6 | 7 | namespace 8 | { 9 | bool cmp_sockaddr_storage(sockaddr_storage& storage, sockaddr_storage& storage2) 10 | { 11 | for (auto i = 0; i < sizeof(sockaddr_storage); ++i) { 12 | auto storage_ptr = reinterpret_cast(&storage); 13 | auto storage2_ptr = reinterpret_cast(&storage2); 14 | if (storage_ptr[i] != storage2_ptr[i]) 15 | return false; 16 | } 17 | return true; 18 | } 19 | } 20 | 21 | TEST_CASE("GetSockAddr for IPv4", "[netutils]") 22 | { 23 | auto loop = uvw::Loop::create(); 24 | sockaddr_storage storage {}; 25 | sockaddr_storage storage2 {}; 26 | auto ip = "220.181.38.148"; 27 | auto port = 443; 28 | int res = ssr_get_sock_addr(loop, ip, port, &storage, true); 29 | REQUIRE(res == 0); 30 | uv_ip4_addr(ip, port, reinterpret_cast(&storage2)); 31 | for (auto i = 0; i < sizeof(sockaddr_storage); ++i) { 32 | auto storage_ptr = reinterpret_cast(&storage); 33 | auto storage2_ptr = reinterpret_cast(&storage2); 34 | REQUIRE(storage_ptr[i] == storage2_ptr[i]); 35 | } 36 | } 37 | 38 | TEST_CASE("GetSockAddr for IPv4 invalid", "[netutils]") 39 | { 40 | auto loop = uvw::Loop::create(); 41 | sockaddr_storage storage {}; 42 | sockaddr_storage storage2 {}; 43 | auto ip = "299.299.299.299"; 44 | auto port = 443; 45 | int res = ssr_get_sock_addr(loop, ip, port, &storage, true); 46 | REQUIRE(res != 0); 47 | } 48 | 49 | TEST_CASE("GetSockAddr for IPv6 invalid", "[netutils]") 50 | { 51 | auto loop = uvw::Loop::create(); 52 | sockaddr_storage storage {}; 53 | sockaddr_storage storage2 {}; 54 | auto ip = "fe80::1::2"; 55 | auto port = 443; 56 | int res = ssr_get_sock_addr(loop, ip, port, &storage, true); 57 | REQUIRE(res != 0); 58 | } 59 | 60 | TEST_CASE("GetSockAddr for IPv6", "[netutils]") 61 | { 62 | auto loop = uvw::Loop::create(); 63 | sockaddr_storage storage {}; 64 | sockaddr_storage storage2 {}; 65 | auto ip = "2607:f8b0:4007:804::200e"; 66 | auto port = 443; 67 | int res = ssr_get_sock_addr(loop, ip, port, &storage, true); 68 | REQUIRE(res == 0); 69 | uv_ip6_addr(ip, port, reinterpret_cast(&storage2)); 70 | for (auto i = 0; i < sizeof(sockaddr_storage); ++i) { 71 | auto storage_ptr = reinterpret_cast(&storage); 72 | auto storage2_ptr = reinterpret_cast(&storage2); 73 | REQUIRE(storage_ptr[i] == storage2_ptr[i]); 74 | } 75 | } 76 | 77 | TEST_CASE("GetSockAddr for host ipv4", "[netutils]") 78 | { 79 | auto loop = uvw::Loop::create(); 80 | sockaddr_storage storage {}; 81 | sockaddr_storage storage2 {}; 82 | auto host = "google.com"; 83 | auto port = 443; 84 | int res = ssr_get_sock_addr(loop, host, port, &storage, false); 85 | REQUIRE(res == 0); 86 | uv_getaddrinfo_t req; 87 | struct addrinfo hints; 88 | char digitBuffer[20] = { 0 }; 89 | sprintf(digitBuffer, "%d", port); 90 | memset(&hints, 0, sizeof(struct addrinfo)); 91 | hints.ai_family = AF_UNSPEC; 92 | hints.ai_socktype = SOCK_STREAM; 93 | res = uv_getaddrinfo(loop->raw(), &req, nullptr, host, digitBuffer, &hints); 94 | REQUIRE(res == 0); 95 | struct addrinfo* rp = nullptr; 96 | std::unique_ptr guard { req.addrinfo, &uv_freeaddrinfo }; 97 | bool equal = false; 98 | for (rp = req.addrinfo; rp != nullptr; rp = rp->ai_next) 99 | if (rp->ai_family == AF_INET) { 100 | if (rp->ai_family == AF_INET) 101 | memcpy(&storage2, rp->ai_addr, sizeof(struct sockaddr_in)); 102 | else if (rp->ai_family == AF_INET6) 103 | memcpy(&storage2, rp->ai_addr, sizeof(struct sockaddr_in6)); 104 | equal = cmp_sockaddr_storage(storage, storage2); 105 | if (equal) 106 | break; 107 | } 108 | REQUIRE(equal == true); 109 | } 110 | 111 | TEST_CASE("GetSockAddr for host ipv6", "[netutils]") 112 | { 113 | auto loop = uvw::Loop::create(); 114 | sockaddr_storage storage {}; 115 | sockaddr_storage storage2 {}; 116 | auto host = "ipv6.google.com"; 117 | auto port = 443; 118 | int res = ssr_get_sock_addr(loop, host, port, &storage, true); 119 | REQUIRE(res == 0); 120 | uv_getaddrinfo_t req; 121 | struct addrinfo hints; 122 | char digitBuffer[20] = { 0 }; 123 | sprintf(digitBuffer, "%d", port); 124 | memset(&hints, 0, sizeof(struct addrinfo)); 125 | hints.ai_family = AF_UNSPEC; 126 | hints.ai_socktype = SOCK_STREAM; 127 | res = uv_getaddrinfo(loop->raw(), &req, nullptr, host, digitBuffer, &hints); 128 | REQUIRE(res == 0); 129 | struct addrinfo* rp = nullptr; 130 | std::unique_ptr guard { req.addrinfo, &uv_freeaddrinfo }; 131 | bool equal = false; 132 | for (rp = req.addrinfo; rp != nullptr; rp = rp->ai_next) 133 | if (rp->ai_family == AF_INET6) { 134 | if (rp->ai_family == AF_INET) 135 | memcpy(&storage2, rp->ai_addr, sizeof(struct sockaddr_in)); 136 | else if (rp->ai_family == AF_INET6) 137 | memcpy(&storage2, rp->ai_addr, sizeof(struct sockaddr_in6)); 138 | equal = cmp_sockaddr_storage(storage, storage2); 139 | if (equal) 140 | break; 141 | } 142 | REQUIRE(equal == true); 143 | } 144 | -------------------------------------------------------------------------------- /src/uvw/thread.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "thread.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE Thread::Thread(ConstructorAccess ca, std::shared_ptr ref, Task t, std::shared_ptr d) noexcept 12 | : UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)} 13 | {} 14 | 15 | 16 | UVW_INLINE void Thread::createCallback(void *arg) { 17 | Thread &thread = *(static_cast(arg)); 18 | thread.task(thread.data); 19 | } 20 | 21 | 22 | UVW_INLINE Thread::Type Thread::self() noexcept { 23 | return uv_thread_self(); 24 | } 25 | 26 | 27 | UVW_INLINE bool Thread::equal(const Thread &tl, const Thread &tr) noexcept { 28 | return !(0 == uv_thread_equal(tl.get(), tr.get())); 29 | } 30 | 31 | 32 | UVW_INLINE Thread::~Thread() noexcept { 33 | join(); 34 | } 35 | 36 | 37 | UVW_INLINE bool Thread::run() noexcept { 38 | return (0 == uv_thread_create(get(), &createCallback, this)); 39 | } 40 | 41 | 42 | UVW_INLINE bool Thread::run(Flags opts, std::size_t stack) noexcept { 43 | uv_thread_options_t params{opts, stack}; 44 | return (0 == uv_thread_create_ex(get(), ¶ms, &createCallback, this)); 45 | } 46 | 47 | 48 | UVW_INLINE bool Thread::join() noexcept { 49 | return (0 == uv_thread_join(get())); 50 | } 51 | 52 | 53 | UVW_INLINE ThreadLocalStorage::ThreadLocalStorage(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref) noexcept 54 | :UnderlyingType{ca, std::move(ref)} 55 | { 56 | uv_key_create(UnderlyingType::get()); 57 | } 58 | 59 | 60 | UVW_INLINE ThreadLocalStorage::~ThreadLocalStorage() noexcept { 61 | uv_key_delete(UnderlyingType::get()); 62 | } 63 | 64 | 65 | UVW_INLINE uv_once_t *Once::guard() noexcept { 66 | static uv_once_t once = UV_ONCE_INIT; 67 | return &once; 68 | } 69 | 70 | 71 | UVW_INLINE Mutex::Mutex(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref, bool recursive) noexcept 72 | : UnderlyingType{ca, std::move(ref)} 73 | { 74 | if(recursive) { 75 | uv_mutex_init_recursive(get()); 76 | } else { 77 | uv_mutex_init(get()); 78 | } 79 | } 80 | 81 | 82 | UVW_INLINE Mutex::~Mutex() noexcept { 83 | uv_mutex_destroy(get()); 84 | } 85 | 86 | 87 | UVW_INLINE void Mutex::lock() noexcept { 88 | uv_mutex_lock(get()); 89 | } 90 | 91 | 92 | UVW_INLINE bool Mutex::tryLock() noexcept { 93 | return (0 == uv_mutex_trylock(get())); 94 | } 95 | 96 | 97 | UVW_INLINE void Mutex::unlock() noexcept { 98 | uv_mutex_unlock(get()); 99 | } 100 | 101 | 102 | UVW_INLINE RWLock::RWLock(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref) noexcept 103 | : UnderlyingType{ca, std::move(ref)} 104 | { 105 | uv_rwlock_init(get()); 106 | } 107 | 108 | 109 | UVW_INLINE RWLock::~RWLock() noexcept { 110 | uv_rwlock_destroy(get()); 111 | } 112 | 113 | 114 | UVW_INLINE void RWLock::rdLock() noexcept { 115 | uv_rwlock_rdlock(get()); 116 | } 117 | 118 | 119 | UVW_INLINE bool RWLock::tryRdLock() noexcept { 120 | return (0 == uv_rwlock_tryrdlock(get())); 121 | } 122 | 123 | 124 | UVW_INLINE void RWLock::rdUnlock() noexcept { 125 | uv_rwlock_rdunlock(get()); 126 | } 127 | 128 | 129 | UVW_INLINE void RWLock::wrLock() noexcept { 130 | uv_rwlock_wrlock(get()); 131 | } 132 | 133 | 134 | UVW_INLINE bool RWLock::tryWrLock() noexcept { 135 | return (0 == uv_rwlock_trywrlock(get())); 136 | } 137 | 138 | 139 | UVW_INLINE void RWLock::wrUnlock() noexcept { 140 | uv_rwlock_wrunlock(get()); 141 | } 142 | 143 | 144 | UVW_INLINE Semaphore::Semaphore(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref, unsigned int value) noexcept 145 | : UnderlyingType{ca, std::move(ref)} 146 | { 147 | uv_sem_init(get(), value); 148 | } 149 | 150 | 151 | UVW_INLINE Semaphore::~Semaphore() noexcept { 152 | uv_sem_destroy(get()); 153 | } 154 | 155 | 156 | UVW_INLINE void Semaphore::post() noexcept { 157 | uv_sem_post(get()); 158 | } 159 | 160 | 161 | UVW_INLINE void Semaphore::wait() noexcept { 162 | uv_sem_wait(get()); 163 | } 164 | 165 | 166 | UVW_INLINE bool Semaphore::tryWait() noexcept { 167 | return (0 == uv_sem_trywait(get())); 168 | } 169 | 170 | 171 | UVW_INLINE Condition::Condition(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref) noexcept 172 | : UnderlyingType{ca, std::move(ref)} 173 | { 174 | uv_cond_init(get()); 175 | } 176 | 177 | 178 | UVW_INLINE Condition::~Condition() noexcept { 179 | uv_cond_destroy(get()); 180 | } 181 | 182 | 183 | UVW_INLINE void Condition::signal() noexcept { 184 | uv_cond_signal(get()); 185 | } 186 | 187 | 188 | UVW_INLINE void Condition::broadcast() noexcept { 189 | uv_cond_broadcast(get()); 190 | } 191 | 192 | 193 | UVW_INLINE void Condition::wait(Mutex &mutex) noexcept { 194 | uv_cond_wait(get(), mutex.get()); 195 | } 196 | 197 | 198 | UVW_INLINE bool Condition::timedWait(Mutex &mutex, uint64_t timeout) noexcept { 199 | return (0 == uv_cond_timedwait(get(), mutex.get(), timeout)); 200 | } 201 | 202 | 203 | UVW_INLINE Barrier::Barrier(UnderlyingType::ConstructorAccess ca, std::shared_ptr ref, unsigned int count) noexcept 204 | : UnderlyingType{ca, std::move(ref)} 205 | { 206 | uv_barrier_init(get(), count); 207 | } 208 | 209 | 210 | UVW_INLINE Barrier::~Barrier() noexcept { 211 | uv_barrier_destroy(get()); 212 | } 213 | 214 | 215 | UVW_INLINE bool Barrier::wait() noexcept { 216 | return (0 == uv_barrier_wait(get())); 217 | } 218 | 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/uvw/dns.cpp: -------------------------------------------------------------------------------- 1 | #ifdef UVW_AS_LIB 2 | #include "dns.h" 3 | #endif 4 | 5 | #include "config.h" 6 | 7 | 8 | namespace uvw { 9 | 10 | 11 | UVW_INLINE AddrInfoEvent::AddrInfoEvent(std::unique_ptr addr) 12 | : data{std::move(addr)} 13 | {} 14 | 15 | 16 | UVW_INLINE NameInfoEvent::NameInfoEvent(const char *host, const char *serv) 17 | : hostname{host}, service{serv} 18 | {} 19 | 20 | 21 | UVW_INLINE void GetAddrInfoReq::addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res) { 22 | auto ptr = reserve(req); 23 | 24 | if(status) { 25 | ptr->publish(ErrorEvent{status}); 26 | } else { 27 | auto data = std::unique_ptr{res, [](addrinfo *addr) { 28 | uv_freeaddrinfo(addr); 29 | }}; 30 | 31 | ptr->publish(AddrInfoEvent{std::move(data)}); 32 | } 33 | } 34 | 35 | 36 | UVW_INLINE void GetAddrInfoReq::nodeAddrInfo(const char *node, const char *service, addrinfo *hints) { 37 | invoke(&uv_getaddrinfo, parent(), get(), &addrInfoCallback, node, service, hints); 38 | } 39 | 40 | 41 | UVW_INLINE auto GetAddrInfoReq::nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints) { 42 | auto req = get(); 43 | auto err = uv_getaddrinfo(parent(), req, nullptr, node, service, hints); 44 | auto data = std::unique_ptr{req->addrinfo, [](addrinfo *addr) { 45 | uv_freeaddrinfo(addr); 46 | }}; 47 | 48 | return std::make_pair(!err, std::move(data)); 49 | } 50 | 51 | 52 | UVW_INLINE void GetAddrInfoReq::nodeAddrInfo(std::string node, addrinfo *hints) { 53 | nodeAddrInfo(node.data(), nullptr, hints); 54 | } 55 | 56 | 57 | UVW_INLINE std::pair> GetAddrInfoReq::nodeAddrInfoSync(std::string node, addrinfo *hints) { 58 | return nodeAddrInfoSync(node.data(), nullptr, hints); 59 | } 60 | 61 | 62 | UVW_INLINE void GetAddrInfoReq::serviceAddrInfo(std::string service, addrinfo *hints) { 63 | nodeAddrInfo(nullptr, service.data(), hints); 64 | } 65 | 66 | 67 | UVW_INLINE std::pair> GetAddrInfoReq::serviceAddrInfoSync(std::string service, addrinfo *hints) { 68 | return nodeAddrInfoSync(nullptr, service.data(), hints); 69 | } 70 | 71 | 72 | UVW_INLINE void GetAddrInfoReq::addrInfo(std::string node, std::string service, addrinfo *hints) { 73 | nodeAddrInfo(node.data(), service.data(), hints); 74 | } 75 | 76 | 77 | UVW_INLINE std::pair> GetAddrInfoReq::addrInfoSync(std::string node, std::string service, addrinfo *hints) { 78 | return nodeAddrInfoSync(node.data(), service.data(), hints); 79 | } 80 | 81 | 82 | UVW_INLINE void GetNameInfoReq::nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { 83 | auto ptr = reserve(req); 84 | 85 | if(status) { 86 | ptr->publish(ErrorEvent{status}); 87 | } else { 88 | ptr->publish(NameInfoEvent{hostname, service}); 89 | } 90 | } 91 | 92 | 93 | UVW_INLINE void GetNameInfoReq::nameInfo(const sockaddr &addr, int flags) { 94 | invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, &addr, flags); 95 | } 96 | 97 | 98 | template 99 | UVW_INLINE void GetNameInfoReq::nameInfo(std::string ip, unsigned int port, int flags) { 100 | typename details::IpTraits::Type addr; 101 | details::IpTraits::addrFunc(ip.data(), port, &addr); 102 | nameInfo(reinterpret_cast(addr), flags); 103 | } 104 | 105 | template 106 | UVW_INLINE void GetNameInfoReq::nameInfo(Addr addr, int flags) { 107 | nameInfo(std::move(addr.ip), addr.port, flags); 108 | } 109 | 110 | UVW_INLINE std::pair> GetNameInfoReq::nameInfoSync(const sockaddr &addr, int flags) { 111 | auto req = get(); 112 | auto err = uv_getnameinfo(parent(), req, nullptr, &addr, flags); 113 | return std::make_pair(!err, std::make_pair(req->host, req->service)); 114 | } 115 | 116 | 117 | template 118 | UVW_INLINE std::pair> GetNameInfoReq::nameInfoSync(std::string ip, unsigned int port, int flags) { 119 | typename details::IpTraits::Type addr; 120 | details::IpTraits::addrFunc(ip.data(), port, &addr); 121 | return nameInfoSync(reinterpret_cast(addr), flags); 122 | } 123 | 124 | 125 | template 126 | UVW_INLINE std::pair> GetNameInfoReq::nameInfoSync(Addr addr, int flags) { 127 | return nameInfoSync(std::move(addr.ip), addr.port, flags); 128 | } 129 | 130 | 131 | // explicit instantiations 132 | 133 | template void GetNameInfoReq::nameInfo(std::string ip, unsigned int port, int flags); 134 | template void GetNameInfoReq::nameInfo(std::string ip, unsigned int port, int flags); 135 | 136 | template void GetNameInfoReq::nameInfo(Addr addr, int flags); 137 | template void GetNameInfoReq::nameInfo(Addr addr, int flags); 138 | 139 | template std::pair> GetNameInfoReq::nameInfoSync(std::string ip, unsigned int port, int flags); 140 | template std::pair> GetNameInfoReq::nameInfoSync(std::string ip, unsigned int port, int flags); 141 | 142 | template std::pair> GetNameInfoReq::nameInfoSync(Addr addr, int flags); 143 | template std::pair> GetNameInfoReq::nameInfoSync(Addr addr, int flags); 144 | 145 | 146 | } 147 | -------------------------------------------------------------------------------- /.github/workflows/build-shadowsocksr-uvw.yml: -------------------------------------------------------------------------------- 1 | name: shadowsocksr build matrix - cmake 2 | 3 | on: 4 | push: 5 | release: 6 | types: [prereleased] 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | qt_version: [5.15.0] 13 | platform: [ubuntu-16.04, macos-latest, windows-latest] 14 | arch: [x86, x64] 15 | include: 16 | - platform: windows-latest 17 | arch: x86 18 | qtarch: win32_msvc2017 19 | - platform: windows-latest 20 | arch: x64 21 | qtarch: win64_msvc2017_64 22 | exclude: 23 | - platform: ubuntu-16.04 24 | arch: x86 25 | - platform: macos-latest 26 | arch: x86 27 | - platform: windows-latest 28 | arch: x86 29 | qt_version: 5.11.1 30 | fail-fast: false 31 | 32 | runs-on: ${{ matrix.platform }} 33 | 34 | steps: 35 | - name: Get the version 36 | id: get_version 37 | shell: bash 38 | run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 39 | - name: Checking out sources 40 | uses: actions/checkout@master 41 | - name: Install Python 3.7 version 42 | uses: actions/setup-python@v1 43 | with: 44 | python-version: '3.7' 45 | architecture: ${{ matrix.arch }} 46 | - name: Restoring submodules 47 | run: git submodule update --init 48 | # ========================================================================================================= 49 | - name: Install MSVC compiler 50 | if: matrix.platform == 'windows-latest' 51 | uses: ilammy/msvc-dev-cmd@v1 52 | with: 53 | toolset: 14.2 54 | arch: ${{ matrix.arch }} 55 | - name: Cache Qt 56 | id: cache-qt 57 | uses: actions/cache@v1 58 | with: 59 | path: ../Qt 60 | key: QtCache-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.qt_version }} 61 | - name: Installing Qt - ${{ matrix.arch }} 62 | uses: jurplel/install-qt-action@v2.5.0 63 | with: 64 | version: ${{ matrix.qt_version }} 65 | arch: ${{ matrix.qtarch }} 66 | cached: ${{ steps.cache-qt.outputs.cache-hit }} 67 | # ========================================================================================================= 68 | - name: Linux - ${{ matrix.qt_version }} - Build preparation - Install Packages 69 | if: matrix.platform == 'ubuntu-16.04' 70 | run: | 71 | sudo add-apt-repository ppa:webispy/grpc 72 | sudo add-apt-repository ppa:carsten-uppenbrink-net/openssl 73 | sudo apt update 74 | sudo apt install -y libssl-dev tree ninja-build 75 | # -------------------------------------------------------- 76 | - name: macOS - ${{ matrix.qt_version }} - Build preparation - Install Packages 77 | if: matrix.platform == 'macos-latest' 78 | run: | 79 | brew reinstall openssl 80 | brew reinstall ninja 81 | # -------------------------------------------------------- 82 | - name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - Build preparation - Download Dependencies 83 | shell: bash 84 | if: matrix.platform == 'windows-latest' 85 | run: | 86 | mkdir -p ./libs 87 | choco install -y ninja 88 | curl -o ./libs/Qv2ray-deps-openssl-${{ matrix.arch }}-windows.7z -L https://github.com/DuckVador/shadowsocksr-uvw-deps/releases/download/release/Qv2ray-deps-openssl-${{ matrix.arch }}-windows.7z 89 | - name: Win-${{ matrix.arch }} - Build preparation - Extract Dependencies 90 | if: matrix.platform == 'windows-latest' 91 | uses: DuckSoft/extract-7z-action@v1.0 92 | with: 93 | pathSource: ./libs/Qv2ray-deps-openssl-${{ matrix.arch }}-windows.7z 94 | pathTarget: ./libs 95 | # ========================================================================================================= Generate MakeFile and Build 96 | - name: macOS - ${{ matrix.qt_version }} - Generate Dependencies and Build 97 | shell: bash 98 | if: matrix.platform == 'macos-latest' 99 | run: | 100 | mkdir build 101 | cd build 102 | cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 -DOPENSSL_LIBRARIES=/usr/local/opt/openssl@1.1/lib 103 | cmake --build . --parallel $(sysctl -n hw.logicalcpu) 104 | # -------------------------------------------------------- 105 | - name: Windows - ${{ matrix.qt_version }} - Generate Dependencies and Build 106 | shell: bash 107 | if: matrix.platform == 'windows-latest' 108 | env: 109 | CC: cl.exe 110 | CXX: cl.exe 111 | run: | 112 | mkdir build 113 | cd build 114 | cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static 115 | cmake --build . --parallel $(nproc) 116 | # -------------------------------------------------------- 117 | - name: Linux - ${{ matrix.qt_version }} - Generate Dependencies and Build 118 | if: matrix.platform == 'ubuntu-16.04' 119 | shell: bash 120 | env: 121 | CC: /usr/bin/gcc-9 122 | CXX: /usr/bin/g++-9 123 | run: | 124 | mkdir build 125 | cd build 126 | cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release 127 | cmake --build . --parallel $(nproc) 128 | 129 | - name: Win-${{ matrix.arch }} - Create 7z Release 130 | if: matrix.platform == 'windows-latest' 131 | uses: DuckSoft/create-7z-action@v1.0 132 | with: 133 | pathSource: ./build/src/ssr-local.exe 134 | pathTarget: ./release.7z 135 | 136 | - name: Unix-${{ matrix.arch }} - Create 7z Release 137 | if: matrix.platform != 'windows-latest' 138 | uses: DuckSoft/create-7z-action@v1.0 139 | with: 140 | pathSource: ./build/src/ssr-local 141 | pathTarget: ./release.7z 142 | 143 | - name: Uploading artifact ${{ matrix.platform }} 144 | uses: actions/upload-artifact@master 145 | with: 146 | name: ssr-local-${{ matrix.platform }}-${{ matrix.arch }}.7z 147 | path: release.7z 148 | 149 | - name: Upload binaries to release 150 | uses: svenstaro/upload-release-action@v1-release 151 | with: 152 | repo_token: ${{ secrets.GITHUB_TOKEN }} 153 | file: release.7z 154 | asset_name: ssr-local-${{ matrix.platform}}-${{ matrix.arch }}.7z 155 | tag: release 156 | overwrite: true 157 | -------------------------------------------------------------------------------- /src/ssr_local.cpp: -------------------------------------------------------------------------------- 1 | #if !defined(_WIN32) 2 | #include 3 | #include 4 | #else 5 | #include "win/getopt.h" 6 | #endif 7 | #include "shadowsocksr.h" 8 | #include "signal.h" 9 | #include "ssrutils.h" 10 | 11 | static void usage() 12 | { 13 | printf("\n"); 14 | printf("shadowsocks-uvw \n\n"); 15 | printf( 16 | " maintained by DuckVador \n\n"); 17 | printf(" usage:\n\n"); 18 | printf(" ssr-local\n"); 19 | printf("\n"); 20 | printf( 21 | " -s Host name or IP address of your remote server.\n"); 22 | printf( 23 | " -p Port number of your remote server.\n"); 24 | printf( 25 | " [-6] Resovle hostname to IPv6 address first.\n"); 26 | printf( 27 | " -b Local address to bind.\n"); 28 | printf( 29 | " -l Port number of your local server.\n"); 30 | printf( 31 | " -k Password of your remote server.\n"); 32 | printf( 33 | " -m Encrypt method: none, table, rc4, rc4-md5,\n"); 34 | printf( 35 | " aes-128-cfb, aes-192-cfb, aes-256-cfb,\n"); 36 | printf( 37 | " aes-128-ctr, aes-192-ctr, aes-256-ctr,\n"); 38 | printf( 39 | " bf-cfb, camellia-128-cfb, camellia-192-cfb,\n"); 40 | printf( 41 | " camellia-256-cfb, cast5-cfb, des-cfb,\n"); 42 | printf( 43 | " idea-cfb, rc2-cfb, seed-cfb, salsa20,\n"); 44 | printf( 45 | " chacha20 and chacha20-ietf.\n"); 46 | printf( 47 | " The default cipher is rc4-md5.\n"); 48 | printf("\n"); 49 | printf( 50 | " [-t ] Socket timeout in seconds.\n"); 51 | printf("\n"); 52 | printf( 53 | " [-O ] protocol: origin, auth_sha1, auth_sha1_v2, auth_sha1_v4,\n"); 54 | printf( 55 | " auth_aes_128_sha1, auth_aes_128_md5, auth_chain_a, auth_chain_b,\n"); 56 | printf( 57 | " auth_chain_c, auth_chain_d, auth_chain_e, auth_chain_f.\n"); 58 | printf("\n"); 59 | printf( 60 | " [-G ] Parameter of your protocol.\n"); 61 | printf( 62 | " [-o ] obfs: plain, http_simple, http_post, tls1.2_ticket_auth.\n"); 63 | printf("\n"); 64 | printf( 65 | " [-g ] Parameter of your obfs.\n"); 66 | printf( 67 | " [-u] Enable UDP relay.\n"); 68 | // printf( 69 | // " [-U] Enable UDP relay and disable TCP relay.\n"); 70 | printf("\n"); 71 | printf( 72 | " [--mtu ] MTU of your network interface.\n"); 73 | printf("\n"); 74 | printf( 75 | " [-v] Verbose mode.\n"); 76 | printf( 77 | " [-h, --help] Print this message.\n"); 78 | printf("\n"); 79 | } 80 | void sigintHandler(int sig_num) 81 | { 82 | /* Reset handler to catch SIGINT next time. 83 | Refer http://en.cppreference.com/w/c/program/signal */ 84 | signal(SIGINT, sigintHandler); 85 | stop_ssr_uv_local_server(); 86 | LOGI("waiting main loop to exit"); 87 | fflush(stdout); 88 | } 89 | 90 | int main(int argc, char** argv) 91 | { 92 | int c; 93 | int option_index = 0; 94 | profile_t p {}; 95 | p.method = "rc4-md5"; 96 | p.local_addr = "0.0.0.0"; 97 | p.remote_host = "127.0.0.1"; 98 | p.remote_port = 0; 99 | p.timeout = 60000; 100 | p.mtu = 1500; 101 | p.obfs = "origin"; 102 | p.obfs_param = ""; 103 | p.protocol = "plain"; 104 | p.protocol_param = ""; 105 | p.password = "shadowsocksr-uvw"; 106 | opterr = 0; 107 | static struct option long_options[] = { 108 | { "mtu", required_argument, 0, 0 }, 109 | { "help", no_argument, 0, 0 }, 110 | { "host", required_argument, 0, 0 }, 111 | { 0, 0, 0, 0 } 112 | }; 113 | while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUvA6" 114 | "O:o:G:g:", 115 | long_options, &option_index)) 116 | != -1) { 117 | switch (c) { 118 | case 0: 119 | if (option_index == 0) { 120 | p.mtu = atoi(optarg); 121 | LOGI("set MTU to %d", p.mtu); 122 | } else if (option_index == 1) { 123 | usage(); 124 | exit(EXIT_SUCCESS); 125 | } else if (option_index == 2) { 126 | p.remote_host = optarg; 127 | } 128 | break; 129 | case 's': 130 | p.remote_host = optarg; 131 | break; 132 | case 'p': 133 | p.remote_port = atoi(optarg); 134 | break; 135 | case 'l': 136 | p.local_port = atoi(optarg); 137 | break; 138 | case 'k': 139 | p.password = optarg; 140 | break; 141 | case 't': 142 | p.timeout = atoi(optarg) * 1000; 143 | break; 144 | case 'O': 145 | p.protocol = optarg; 146 | break; 147 | case 'm': 148 | p.method = optarg; 149 | break; 150 | case 'o': 151 | p.obfs = optarg; 152 | break; 153 | case 'G': 154 | p.protocol_param = optarg; 155 | break; 156 | case 'g': 157 | p.obfs_param = optarg; 158 | break; 159 | case '6': 160 | p.ipv6first = 1; 161 | break; 162 | case 'b': 163 | p.local_addr = optarg; 164 | break; 165 | case 'u': 166 | p.mode = 1; 167 | break; 168 | case 'v': 169 | p.verbose = 1; 170 | break; 171 | case 'h': 172 | usage(); 173 | exit(EXIT_SUCCESS); 174 | case '?': 175 | // The option character is not recognized. 176 | LOGE("Unrecognized option: %s", optarg); 177 | opterr = 1; 178 | break; 179 | } 180 | } 181 | if (p.local_port == 0 || p.remote_port == 0) { 182 | opterr = 1; 183 | } 184 | if (opterr) { 185 | usage(); 186 | exit(EXIT_FAILURE); 187 | } 188 | USE_TTY(); 189 | signal(SIGINT, sigintHandler); 190 | start_ssr_uv_local_server(p); 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/encrypt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * encrypt.h - Define the enryptor's interface 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the shadowsocks-libev. 7 | * 8 | * shadowsocks-libev is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * shadowsocks-libev is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with shadowsocks-libev; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _ENCRYPT_H 24 | #define _ENCRYPT_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | #ifdef HAVE_CONFIG_H 31 | #include "config.h" 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #if defined(USE_CRYPTO_OPENSSL) 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | typedef EVP_CIPHER cipher_kt_t; 46 | typedef EVP_CIPHER_CTX cipher_evp_t; 47 | typedef EVP_MD digest_type_t; 48 | #define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH 49 | #define MAX_IV_LENGTH EVP_MAX_IV_LENGTH 50 | #define MAX_MD_SIZE EVP_MAX_MD_SIZE 51 | 52 | #elif defined(USE_CRYPTO_POLARSSL) 53 | 54 | #include 55 | #include 56 | typedef cipher_info_t cipher_kt_t; 57 | typedef cipher_context_t cipher_evp_t; 58 | typedef md_info_t digest_type_t; 59 | #define MAX_KEY_LENGTH 64 60 | #define MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH 61 | #define MAX_MD_SIZE POLARSSL_MD_MAX_SIZE 62 | 63 | #elif defined(USE_CRYPTO_MBEDTLS) 64 | 65 | #include 66 | #include 67 | typedef mbedtls_cipher_info_t cipher_kt_t; 68 | typedef mbedtls_cipher_context_t cipher_evp_t; 69 | typedef mbedtls_md_info_t digest_type_t; 70 | #define MAX_KEY_LENGTH 64 71 | #define MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH 72 | #define MAX_MD_SIZE MBEDTLS_MD_MAX_SIZE 73 | 74 | /* we must have MBEDTLS_CIPHER_MODE_CFB defined */ 75 | #if !defined(MBEDTLS_CIPHER_MODE_CFB) 76 | #error Cipher Feedback mode a.k.a CFB not supported by your mbed TLS. 77 | #endif 78 | 79 | #endif 80 | 81 | #ifdef USE_CRYPTO_APPLECC 82 | 83 | #include 84 | 85 | #define kCCAlgorithmInvalid UINT32_MAX 86 | #define kCCContextValid 0 87 | #define kCCContextInvalid -1 88 | 89 | typedef struct 90 | { 91 | CCCryptorRef cryptor; 92 | int valid; 93 | CCOperation encrypt; 94 | CCAlgorithm cipher; 95 | CCMode mode; 96 | CCPadding padding; 97 | uint8_t iv[MAX_IV_LENGTH]; 98 | uint8_t key[MAX_KEY_LENGTH]; 99 | size_t iv_len; 100 | size_t key_len; 101 | } cipher_cc_t; 102 | 103 | #endif 104 | 105 | typedef struct 106 | { 107 | uint8_t* enc_table; 108 | uint8_t* dec_table; 109 | uint8_t enc_key[MAX_KEY_LENGTH]; 110 | int enc_key_len; 111 | int enc_iv_len; 112 | int enc_method; 113 | 114 | struct cache* iv_cache; 115 | } cipher_env_t; 116 | 117 | typedef struct 118 | { 119 | cipher_evp_t* evp; 120 | #ifdef USE_CRYPTO_APPLECC 121 | cipher_cc_t cc; 122 | #endif 123 | uint8_t iv[MAX_IV_LENGTH]; 124 | } cipher_ctx_t; 125 | 126 | typedef struct 127 | { 128 | cipher_kt_t* info; 129 | size_t iv_len; 130 | size_t key_len; 131 | } cipher_t; 132 | 133 | #ifdef HAVE_STDINT_H 134 | #include 135 | #elif HAVE_INTTYPES_H 136 | #include 137 | #endif 138 | 139 | #define SODIUM_BLOCK_SIZE 64 140 | 141 | enum crpher_index { 142 | NONE, 143 | TABLE, 144 | RC4, 145 | RC4_MD5_6, 146 | RC4_MD5, 147 | AES_128_CFB, 148 | AES_192_CFB, 149 | AES_256_CFB, 150 | AES_128_CTR, 151 | AES_192_CTR, 152 | AES_256_CTR, 153 | BF_CFB, 154 | CAMELLIA_128_CFB, 155 | CAMELLIA_192_CFB, 156 | CAMELLIA_256_CFB, 157 | CAST5_CFB, 158 | DES_CFB, 159 | IDEA_CFB, 160 | RC2_CFB, 161 | SEED_CFB, 162 | SALSA20, 163 | CHACHA20, 164 | CHACHA20IETF, 165 | CIPHER_NUM, 166 | }; 167 | 168 | #define ADDRTYPE_MASK 0xEF 169 | 170 | #define MD5_BYTES 16U 171 | #define SHA1_BYTES 20U 172 | 173 | typedef struct buffer 174 | { 175 | size_t idx; 176 | size_t len; 177 | size_t capacity; 178 | char* array; 179 | } buffer_t; 180 | 181 | typedef struct enc_ctx 182 | { 183 | uint8_t init; 184 | uint64_t counter; 185 | cipher_ctx_t evp; 186 | } enc_ctx_t; 187 | 188 | void bytes_to_key_with_size(const char* pass, size_t len, uint8_t* md, size_t md_size); 189 | 190 | int rand_bytes(uint8_t* output, int len); 191 | 192 | int ss_encrypt_all(cipher_env_t* env, buffer_t* plaintext, size_t capacity); 193 | int ss_decrypt_all(cipher_env_t* env, buffer_t* ciphertext, size_t capacity); 194 | int ss_encrypt(cipher_env_t* env, buffer_t* plaintext, enc_ctx_t* ctx, size_t capacity); 195 | int ss_decrypt(cipher_env_t* env, buffer_t* ciphertext, enc_ctx_t* ctx, size_t capacity); 196 | 197 | int enc_init(cipher_env_t* env, const char* pass, const char* method); 198 | void enc_release(cipher_env_t* env); 199 | void enc_ctx_init(cipher_env_t* env, enc_ctx_t* ctx, int enc); 200 | void enc_ctx_release(cipher_env_t* env, enc_ctx_t* ctx); 201 | int enc_get_iv_len(cipher_env_t* env); 202 | uint8_t* enc_get_key(cipher_env_t* env); 203 | int enc_get_key_len(cipher_env_t* env); 204 | void cipher_context_release(cipher_env_t* env, cipher_ctx_t* ctx); 205 | unsigned char* enc_md5(const unsigned char* d, size_t n, unsigned char* md); 206 | 207 | int ss_md5_hmac_with_key(char* auth, char* msg, int msg_len, uint8_t* auth_key, int key_len); 208 | int ss_md5_hash_func(char* auth, char* msg, int msg_len); 209 | int ss_sha1_hmac_with_key(char* auth, char* msg, int msg_len, uint8_t* auth_key, int key_len); 210 | int ss_sha1_hash_func(char* auth, char* msg, int msg_len); 211 | int ss_aes_128_cbc(char* encrypt, char* out_data, char* key); 212 | int ss_encrypt_buffer(cipher_env_t* env, enc_ctx_t* ctx, char* in, size_t in_size, char* out, size_t* out_size); 213 | int ss_decrypt_buffer(cipher_env_t* env, enc_ctx_t* ctx, char* in, size_t in_size, char* out, size_t* out_size); 214 | 215 | int balloc(buffer_t* ptr, size_t capacity); 216 | int brealloc(buffer_t* ptr, size_t len, size_t capacity); 217 | void bfree(buffer_t* ptr); 218 | 219 | // extern cipher_env_t cipher_env; 220 | 221 | #ifdef __cplusplus 222 | } 223 | #endif 224 | #endif // _ENCRYPT_H 225 | --------------------------------------------------------------------------------