├── .gitmodules ├── kcp ├── Makefile ├── ikcp.h └── ikcp.c ├── misc ├── ss-local.json ├── ss-server.json ├── ss-local └── ss-server ├── .gitignore ├── src ├── disk_cache.h ├── select_poller.h ├── utest.h ├── listener.h ├── epoll_poller.h ├── udppacket_sender.h ├── fasttun_base.cpp ├── disk_cache.cpp ├── event_poller.h ├── udppacket_sender.cpp ├── epoll_poller.cpp ├── Makefile ├── connection.h ├── event_poller.cpp ├── utest.cpp ├── fast_connection.h ├── cache.h ├── listener.cpp ├── fasttun_base.h ├── select_poller.cpp ├── message_receiver.h ├── fast_connection.cpp ├── test.cpp ├── kcp_tunnel.inl ├── connection.cpp ├── kcp_tunnel.h ├── client.cpp └── server.cpp ├── Makefile ├── README.md └── script ├── tun-cli └── tun-svr /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cill"] 2 | path = cill 3 | url = git@github.com:ruleless/cill.git 4 | -------------------------------------------------------------------------------- /kcp/Makefile: -------------------------------------------------------------------------------- 1 | phonyt:= allt 2 | 3 | ROOT:= .. 4 | LIBPATH:= $(ROOT)/lib 5 | 6 | LIB:= libkcp.a 7 | 8 | include $(ROOT)/cill/cbuild.mak 9 | -------------------------------------------------------------------------------- /misc/ss-local.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1", 3 | "server_port": 5085, 4 | "local_address": "0.0.0.0", 5 | "local_port": 1085, 6 | "password": "", 7 | "timeout": 1000, 8 | "method": "rc4-md5", 9 | } 10 | -------------------------------------------------------------------------------- /misc/ss-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1", 3 | "server_port": 5050, 4 | "local_address": "0.0.0.0", 5 | "local_port": 1050, 6 | "password": "", 7 | "timeout": 1000, 8 | "method": "rc4-md5", 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.o 3 | *.a 4 | *.d 5 | *.d* 6 | *.ncb 7 | *.suo 8 | *.log 9 | *.idc 10 | *.ini 11 | *.user 12 | *.obj 13 | *.exe 14 | *.ilk 15 | *.pdb 16 | *.lib 17 | *.html 18 | *.exp 19 | Debug/ 20 | Obj/ 21 | lib/ 22 | main 23 | temp 24 | tmp 25 | cat 26 | QueueTest 27 | GPATH 28 | GRTAGS 29 | GTAGS 30 | -------------------------------------------------------------------------------- /src/disk_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISKCACHE_H__ 2 | #define __DISKCACHE_H__ 3 | 4 | #include "fasttun_base.h" 5 | 6 | NAMESPACE_BEG(tun) 7 | 8 | class DiskCache 9 | { 10 | public: 11 | DiskCache() 12 | :mpFile(NULL) 13 | {} 14 | 15 | virtual ~DiskCache(); 16 | 17 | ssize_t write(const void *data, size_t datalen); 18 | ssize_t read(void *data, size_t datalen); 19 | size_t peeksize(); 20 | 21 | void rollback(size_t n); 22 | 23 | void clear(); 24 | 25 | private: 26 | bool _createFile(); 27 | 28 | private: 29 | FILE *mpFile; 30 | }; 31 | 32 | NAMESPACE_END // namespace tun 33 | 34 | #endif // __DISKCACHE_H__ 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dirs:= cill 2 | dirs+= kcp 3 | dirs+= src 4 | CONF_CONTENT = "" 5 | 6 | include cill/build.mak 7 | 8 | install-cli: 9 | $(MAKE) -C src install-cli 10 | install-svr: 11 | $(MAKE) -C src install-svr 12 | 13 | uninstall: 14 | $(MAKE) -C src uninstall 15 | 16 | conf: 17 | echo "[local]" > /etc/fast-tun.ini 18 | echo "listen=127.0.0.1:5085" >> /etc/fast-tun.ini 19 | echo "remote=127.0.0.1:29905" >> /etc/fast-tun.ini 20 | echo "kcpremote=127.0.0.1:29905" >> /etc/fast-tun.ini 21 | echo "" >> /etc/fast-tun.ini 22 | echo "[server]" >> /etc/fast-tun.ini 23 | echo "listen=0.0.0.0:29905" >> /etc/fast-tun.ini 24 | echo "connect=0.0.0.0:5080" >> /etc/fast-tun.ini 25 | echo "kcplisten=0.0.0.0:29905" >> /etc/fast-tun.ini 26 | -------------------------------------------------------------------------------- /src/select_poller.h: -------------------------------------------------------------------------------- 1 | #ifndef __SELECTPOLLER_H__ 2 | #define __SELECTPOLLER_H__ 3 | 4 | #include "event_poller.h" 5 | 6 | NAMESPACE_BEG(tun) 7 | 8 | class SelectPoller : public EventPoller 9 | { 10 | public: 11 | SelectPoller(); 12 | protected: 13 | virtual bool doRegisterForRead(int fd); 14 | virtual bool doRegisterForWrite(int fd); 15 | 16 | virtual bool doDeregisterForRead(int fd); 17 | virtual bool doDeregisterForWrite(int fd); 18 | 19 | virtual int processPendingEvents(double maxWait); 20 | private: 21 | void handleNotifications(int &countReady, fd_set &readFDs, fd_set &writeFDs); 22 | 23 | fd_set mFdReadSet; 24 | fd_set mFdWriteSet; 25 | 26 | int mMaxFd; 27 | int mFdWriteCount; 28 | }; 29 | 30 | NAMESPACE_END // namespace tun 31 | 32 | #endif // __SELECTPOLLER_H__ 33 | -------------------------------------------------------------------------------- /src/utest.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTEST_H__ 2 | #define __UTEST_H__ 3 | 4 | #include "cppunit/TestFixture.h" 5 | #include "cppunit/extensions/HelperMacros.h" 6 | 7 | #include "fasttun_base.h" 8 | #include "message_receiver.h" 9 | #include "disk_cache.h" 10 | 11 | class UTest : public CppUnit::TestFixture 12 | { 13 | CPPUNIT_TEST_SUITE(UTest); 14 | CPPUNIT_TEST(testMessageReceiver); 15 | CPPUNIT_TEST(testDiskCache); 16 | CPPUNIT_TEST_SUITE_END(); 17 | public: 18 | UTest() 19 | {} 20 | 21 | virtual ~UTest(); 22 | 23 | virtual void setUp(); 24 | 25 | virtual void tearDown(); 26 | 27 | void testMessageReceiver(); 28 | void _onRecvMessage(const void *data, uint16 datalen, void*); 29 | void _onRecvMsgError(void *); 30 | 31 | void testDiskCache(); 32 | }; 33 | 34 | #endif // __UTEST_H__ 35 | -------------------------------------------------------------------------------- /src/listener.h: -------------------------------------------------------------------------------- 1 | #ifndef __LISTENER_H__ 2 | #define __LISTENER_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "event_poller.h" 6 | 7 | NAMESPACE_BEG(tun) 8 | 9 | class Listener : InputNotificationHandler 10 | { 11 | public: 12 | struct Handler 13 | { 14 | virtual void onAccept(int connfd) = 0; 15 | }; 16 | 17 | Listener(EventPoller *poller) 18 | :mFd(-1) 19 | ,mHandler(NULL) 20 | ,mEventPoller(poller) 21 | { 22 | assert(mEventPoller && "Listener::mEventPoller != NULL"); 23 | } 24 | 25 | virtual ~Listener(); 26 | 27 | bool initialise(const char *ip, int port); 28 | bool initialise(const SA *sa, socklen_t salen); 29 | void finalise(); 30 | 31 | inline void setEventHandler(Handler *h) 32 | { 33 | mHandler = h; 34 | } 35 | 36 | // InputNotificationHandler 37 | virtual int handleInputNotification(int fd); 38 | private: 39 | int mFd; 40 | Handler *mHandler; 41 | 42 | EventPoller *mEventPoller; 43 | }; 44 | 45 | NAMESPACE_END // namespace tun 46 | 47 | #endif // __LISTENER_H__ 48 | -------------------------------------------------------------------------------- /src/epoll_poller.h: -------------------------------------------------------------------------------- 1 | #ifndef __POLLEREPOLL_H__ 2 | #define __POLLEREPOLL_H__ 3 | 4 | #include "event_poller.h" 5 | 6 | #ifdef HAS_EPOLL 7 | 8 | NAMESPACE_BEG(tun) 9 | 10 | class EpollPoller : public EventPoller 11 | { 12 | public: 13 | EpollPoller(int expectedSize = 20); 14 | virtual ~EpollPoller(); 15 | 16 | virtual int getFileDescriptor() const 17 | { 18 | return mEpfd; 19 | } 20 | protected: 21 | virtual bool doRegisterForRead(int fd) 22 | { 23 | return this->doRegister(fd, true, true); 24 | } 25 | 26 | virtual bool doRegisterForWrite(int fd) 27 | { 28 | return this->doRegister(fd, false, true); 29 | } 30 | 31 | virtual bool doDeregisterForRead(int fd) 32 | { 33 | return this->doRegister(fd, true, false); 34 | } 35 | 36 | virtual bool doDeregisterForWrite(int fd) 37 | { 38 | return this->doRegister(fd, false, false); 39 | } 40 | 41 | virtual int processPendingEvents(double maxWait); 42 | 43 | bool doRegister(int fd, bool isRead, bool isRegister); 44 | private: 45 | int mEpfd; 46 | }; 47 | 48 | NAMESPACE_END // namespace tun 49 | 50 | #endif // HAS_EPOLL 51 | #endif // __POLLEREPOLL_H__ 52 | -------------------------------------------------------------------------------- /src/udppacket_sender.h: -------------------------------------------------------------------------------- 1 | #ifndef __UDPPACKETSENDER_H__ 2 | #define __UDPPACKETSENDER_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "event_poller.h" 6 | 7 | NAMESPACE_BEG(tun) 8 | 9 | struct IUdpSender 10 | { 11 | virtual int processSend(const void *data, size_t datalen) = 0; 12 | virtual void regOutputNotification(OutputNotificationHandler *p) = 0; 13 | virtual void unregOutputNotification(OutputNotificationHandler *p) = 0; 14 | }; 15 | 16 | class UdpPacketSender : public OutputNotificationHandler 17 | { 18 | public: 19 | UdpPacketSender(IUdpSender *pSender) 20 | :mpSender(pSender) 21 | ,mbRegForWrite(false) 22 | ,mPacketList() 23 | {} 24 | 25 | virtual ~UdpPacketSender(); 26 | 27 | void send(const void *data, size_t datalen); 28 | 29 | // OutputNotificationHandler 30 | virtual int handleOutputNotification(int fd); 31 | 32 | private: 33 | void tryRegWriteEvent(); 34 | void tryUnregWriteEvent(); 35 | 36 | bool tryFlushRemainPacket(); 37 | void cachePacket(const void *data, size_t datalen); 38 | 39 | private: 40 | typedef std::list PacketList; 41 | 42 | IUdpSender *mpSender; 43 | 44 | bool mbRegForWrite; 45 | PacketList mPacketList; 46 | }; 47 | 48 | NAMESPACE_END // namespace tun 49 | 50 | #endif // __UDPPACKETSENDER_H__ 51 | -------------------------------------------------------------------------------- /src/fasttun_base.cpp: -------------------------------------------------------------------------------- 1 | #include "fasttun_base.h" 2 | 3 | #include 4 | 5 | NAMESPACE_BEG(tun) 6 | 7 | void daemonize(const char *path) 8 | { 9 | /* Our process ID and Session ID */ 10 | pid_t pid, sid; 11 | 12 | /* Fork off the parent process */ 13 | pid = fork(); 14 | if (pid < 0) { 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | /* If we got a good PID, then 19 | * we can exit the parent process. */ 20 | if (pid > 0) { 21 | FILE *file = fopen(path, "w"); 22 | if (file == NULL) { 23 | exit(EXIT_FAILURE); 24 | } 25 | 26 | fprintf(file, "%d", (int)pid); 27 | fclose(file); 28 | exit(EXIT_SUCCESS); 29 | } 30 | 31 | /* Change the file mode mask */ 32 | umask(0); 33 | 34 | /* Create a new SID for the child process */ 35 | sid = setsid(); 36 | if (sid < 0) { 37 | /* Log the failure */ 38 | exit(EXIT_FAILURE); 39 | } 40 | 41 | /* Change the current working directory */ 42 | if ((chdir("/")) < 0) { 43 | /* Log the failure */ 44 | exit(EXIT_FAILURE); 45 | } 46 | 47 | /* Close out the standard file descriptors */ 48 | close(STDIN_FILENO); 49 | close(STDOUT_FILENO); 50 | close(STDERR_FILENO); 51 | } 52 | 53 | void print_stack_frames() 54 | { 55 | int j, nptrs; 56 | 57 | #define SIZE 100 58 | void *buffer[100]; 59 | char **strings; 60 | 61 | nptrs = backtrace(buffer, SIZE); 62 | strings = backtrace_symbols(buffer, nptrs); 63 | if (strings == NULL) 64 | { 65 | perror("backtrace_symbols"); 66 | exit(EXIT_FAILURE); 67 | } 68 | 69 | for (j = 0; j < nptrs; j++) 70 | printf("%s\n", strings[j]); 71 | 72 | free(strings); 73 | } 74 | 75 | NAMESPACE_END // namespace tun 76 | -------------------------------------------------------------------------------- /src/disk_cache.cpp: -------------------------------------------------------------------------------- 1 | #include "disk_cache.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | DiskCache::~DiskCache() 6 | { 7 | if (mpFile) 8 | fclose(mpFile); 9 | } 10 | 11 | ssize_t DiskCache::write(const void *data, size_t datalen) 12 | { 13 | assert(data && datalen > 0); 14 | if (NULL == mpFile) 15 | _createFile(); 16 | if (NULL == mpFile) 17 | return -1; 18 | 19 | long curpos = ftell(mpFile); 20 | if (curpos < 0) 21 | return -10; 22 | if (fseek(mpFile, 0, SEEK_END) < 0) 23 | return -11; 24 | 25 | if (fwrite(&datalen, 1, sizeof(datalen), mpFile) != sizeof(datalen)) 26 | return -2; 27 | if (fwrite(data, 1, datalen, mpFile) != datalen) 28 | return -3; 29 | 30 | fseek(mpFile, curpos, SEEK_SET); 31 | return datalen; 32 | } 33 | 34 | ssize_t DiskCache::read(void *data, size_t datalen) 35 | { 36 | if (NULL == mpFile) 37 | return 0; 38 | 39 | size_t peeksz = peeksize(); 40 | if (0 == peeksz) 41 | return 0; 42 | if (datalen < peeksz) 43 | return -2; 44 | 45 | fseek(mpFile, sizeof(peeksz), SEEK_CUR); 46 | return fread(data, 1, peeksz, mpFile); 47 | } 48 | 49 | size_t DiskCache::peeksize() 50 | { 51 | if (NULL == mpFile) 52 | return 0; 53 | 54 | size_t peeksz = 0; 55 | if (fread(&peeksz, 1, sizeof(peeksz), mpFile) != sizeof(peeksz)) 56 | return 0; 57 | 58 | fseek(mpFile, -sizeof(peeksz), SEEK_CUR); 59 | return peeksz; 60 | } 61 | 62 | void DiskCache::rollback(size_t n) 63 | { 64 | if (mpFile) 65 | fseek(mpFile, -(n+sizeof(size_t)), SEEK_CUR); 66 | } 67 | 68 | void DiskCache::clear() 69 | { 70 | if (mpFile) 71 | { 72 | fclose(mpFile); 73 | mpFile = NULL; 74 | } 75 | } 76 | 77 | bool DiskCache::_createFile() 78 | { 79 | if (mpFile) 80 | fclose(mpFile); 81 | 82 | mpFile = tmpfile(); 83 | return mpFile != NULL; 84 | } 85 | 86 | NAMESPACE_END // namespace tun 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 快速端口转发工具 2 | 3 | ## 简介 4 | 5 | 本项目是基于KCP开发的快速端口转发工具。 6 | 7 | 在介绍本项目之前先介绍几个概念。在C/S架构的程序体系中,有若干客户端(C)和少数服务端(S)。 8 | 客户端一般运行在用户电脑上,而服务端则部署到服务器提供商或云上。 9 | 不同的C/S软件提供不同的服务,内部的工作原理和机制也大不相同, 10 | 但在进行网络数据交换时,所有的C/S软件都有类似的工作模式。 11 | 12 | 服务端在启动时会绑定众所周知的IP和端口,客户端绑定临时IP和端口与服务端建立连接, 13 | 之后,C/S通过常用网络通信协议进行数据交换。 14 | 15 | 本项目工作在任何基于TCP协议的C/S软件之间,充当它们之间的 "代理人"。 16 | 我们使用tun-cli表示本项目客户端,使用tun-svr表示本项目服务端。 17 | 使用本项目的C/S软件不再直接进行网络通信。 18 | 我们以 [shadowsocks](https://github.com/shadowsocks/shadowsocks-libev) 19 | 为例简要地说明使用本项目后的C/S软件的通信过程。shadowsocks 的客户端为 ss-local, 20 | 服务端为 ss-server 。 21 | 22 | 首先 tun-cli 绑定固定的IP和端口,ss-local 之前指向 ss-server 的服务端地址改而指向 tun-cli 所绑定的地址。 23 | 此后,ss-local 的通信对象实际是 tun-cli ,但 tun-cli 是不能直接为 ss-local 提供服务的。 24 | tun-cli 与 tun-svr 建立通信管道,tun-cli 将从 ss-local 收集的数据直接发往 tun-svr。 25 | tun-svr 将"冒充" ss-local 与 ss-server 进行分组交换,而 tun-svr 从 ss-server 获取的数据将直接发送给 tun-cli。 26 | tun-cli 将从 tun-svr 收到的数据转发给 ss-local。这样,ss-local 与 ss-server 就完成了一次通信。 27 | 28 | 上面描述的各程序具有如下关系图: 29 | 30 | ![](http://ruleless.github.io/images/github/fast-tun.png) 31 | 32 | ## 意义 33 | 34 | 在稳定、高速的网络环境下,没有必要大费周章地使用本项目来代理C/S软件的网络封包交换。 35 | 但国内很大部分网络用户的网络环境常常是不稳定和低速的,在浏览国外网站的时候尤其让人伤神。 36 | 那么,这个时候利用本项目加速网络封包交换就显得很有必要了。 37 | 38 | ## 平台 39 | 40 | 理论上,本项目支持任何 Linux 发行版,并可通过适当修改移植到 Windows 平台。 41 | 但基于条件限制,本项目只在 CentoOS 5.x 和 CentOS 6.x 平台下编译并运行过。 42 | 43 | ## 编译 44 | 45 | + `make` 编译!成功后,会在 src 目录下生成 client.out 和 server.out 文件。 46 | + `sudo make conf` 在 /etc 目录下生成示例配置文件fast-tun.ini,注意,该配置文件需要用户根据具体情况进行修改 47 | + `sudo make install-cli` 将客户端(client.out)安装为服务。 48 | + `sudo make install-svr` 将服务端(server.out)安装为服务。 49 | + `sudo make uninstall` 卸载 50 | 51 | ## 配置 52 | 53 | ``` shell 54 | [local] 55 | listen=127.0.0.1:5085 # tun-cli绑定的地址 56 | remote=45.63.60.117:519 # tun-cli与绑定该地址的tun-svr建立TCP通信管道 57 | kcpremote=45.63.60.117:443 # tun-cli与绑定该地址的tun-svr建立快速通信管道 58 | 59 | [server] 60 | listen=0.0.0.0:519 # tun-svr 绑定的TCP地址 61 | kcplisten=0.0.0.0:443 # tun-svr 绑定的UDP地址(用于快速通信管道) 62 | connect=127.0.0.1:5080 # 被代理的C/S软件的S端的监听地址 63 | ``` 64 | 65 | 一份常见的配置如上所示。在充分理解本项目的原理的基础上,很容易得出自己生产环境下的配置。 66 | -------------------------------------------------------------------------------- /src/event_poller.h: -------------------------------------------------------------------------------- 1 | #ifndef __EVENTPOLLOER_H__ 2 | #define __EVENTPOLLOER_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include 6 | 7 | #ifndef _WIN32 8 | #define HAS_EPOLL 9 | #endif 10 | 11 | NAMESPACE_BEG(tun) 12 | 13 | class InputNotificationHandler 14 | { 15 | public: 16 | virtual ~InputNotificationHandler() {}; 17 | virtual int handleInputNotification(int fd) = 0; 18 | }; 19 | 20 | class OutputNotificationHandler 21 | { 22 | public: 23 | virtual ~OutputNotificationHandler() {}; 24 | virtual int handleOutputNotification(int fd) = 0; 25 | }; 26 | 27 | class EventPoller 28 | { 29 | public: 30 | EventPoller(); 31 | virtual ~EventPoller(); 32 | 33 | bool registerForRead(int fd, InputNotificationHandler *handler); 34 | bool registerForWrite(int fd, OutputNotificationHandler *handler); 35 | 36 | bool deregisterForRead(int fd); 37 | bool deregisterForWrite(int fd); 38 | 39 | virtual int processPendingEvents(double maxWait) = 0; 40 | virtual int getFileDescriptor() const; 41 | 42 | void clearSpareTime() 43 | { 44 | mSpareTime = 0; 45 | } 46 | uint64 spareTime() const 47 | { 48 | return mSpareTime; 49 | } 50 | 51 | InputNotificationHandler *findForRead(int fd); 52 | OutputNotificationHandler *findForWrite(int fd); 53 | protected: 54 | virtual bool doRegisterForRead(int fd) = 0; 55 | virtual bool doRegisterForWrite(int fd) = 0; 56 | 57 | virtual bool doDeregisterForRead(int fd) = 0; 58 | virtual bool doDeregisterForWrite(int fd) = 0; 59 | 60 | bool triggerRead(int fd); 61 | bool triggerWrite(int fd); 62 | bool triggerError(int fd); 63 | 64 | bool isRegistered(int fd, bool isForRead) const; 65 | 66 | int recalcMaxFD() const; 67 | protected: 68 | uint64 mSpareTime; 69 | private: 70 | typedef std::map FDReadHandlers; 71 | typedef std::map FDWriteHandlers; 72 | 73 | FDReadHandlers mFdReadHandlers; 74 | FDWriteHandlers mFdWriteHandlers; 75 | }; 76 | 77 | NAMESPACE_END // namespace tun 78 | 79 | #endif // __EVENTPOLLOER_H__ 80 | -------------------------------------------------------------------------------- /src/udppacket_sender.cpp: -------------------------------------------------------------------------------- 1 | #include "udppacket_sender.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | UdpPacketSender::~UdpPacketSender() 6 | { 7 | tryUnregWriteEvent(); 8 | PacketList::iterator it = mPacketList.begin(); 9 | for (; it != mPacketList.end(); ++it) 10 | delete *it; 11 | mPacketList.clear(); 12 | } 13 | 14 | void UdpPacketSender::send(const void *data, size_t datalen) 15 | { 16 | if (tryFlushRemainPacket()) 17 | { 18 | int sentlen = mpSender->processSend(data, datalen); 19 | // int sentlen = -1; 20 | if (sentlen == (int)datalen) 21 | return; 22 | } 23 | 24 | cachePacket(data, datalen); 25 | tryRegWriteEvent(); 26 | } 27 | 28 | int UdpPacketSender::handleOutputNotification(int fd) 29 | { 30 | tryFlushRemainPacket(); 31 | return 0; 32 | } 33 | 34 | void UdpPacketSender::tryRegWriteEvent() 35 | { 36 | if (!mbRegForWrite) 37 | { 38 | mbRegForWrite = true; 39 | mpSender->regOutputNotification(this); 40 | } 41 | } 42 | 43 | void UdpPacketSender::tryUnregWriteEvent() 44 | { 45 | if (mbRegForWrite) 46 | { 47 | mbRegForWrite = false; 48 | mpSender->unregOutputNotification(this); 49 | } 50 | } 51 | 52 | bool UdpPacketSender::tryFlushRemainPacket() 53 | { 54 | if (mPacketList.empty()) 55 | { 56 | return true; 57 | } 58 | 59 | PacketList::iterator it = mPacketList.begin(); 60 | for (; it != mPacketList.end();) 61 | { 62 | Packet *p = *it; 63 | int sentlen = mpSender->processSend(p->buf, p->buflen); 64 | 65 | if (p->buflen == (size_t)sentlen) 66 | { 67 | delete p; 68 | mPacketList.erase(it++); 69 | continue; 70 | } 71 | 72 | break; 73 | } 74 | 75 | if (mPacketList.empty()) 76 | { 77 | tryUnregWriteEvent(); 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | void UdpPacketSender::cachePacket(const void *data, size_t datalen) 85 | { 86 | Packet *p = new Packet(); assert(p && "udppacket != NULL"); 87 | p->buf = (char *)malloc(datalen); assert(p->buf && "udppacket->buf != NULL"); 88 | memcpy(p->buf, data, datalen); 89 | p->buflen = datalen; 90 | mPacketList.push_back(p); 91 | } 92 | 93 | NAMESPACE_END // namespace tun 94 | -------------------------------------------------------------------------------- /src/epoll_poller.cpp: -------------------------------------------------------------------------------- 1 | #include "epoll_poller.h" 2 | 3 | #ifdef HAS_EPOLL 4 | 5 | #include 6 | 7 | NAMESPACE_BEG(tun) 8 | 9 | EpollPoller::EpollPoller(int expectedSize) 10 | { 11 | mEpfd = epoll_create(expectedSize); 12 | if (mEpfd == -1) 13 | { 14 | ErrorPrint("EpollPoller::EpollPoller() epoll_create failed err:%s", coreStrError()); 15 | } 16 | } 17 | 18 | EpollPoller::~EpollPoller() 19 | { 20 | if (mEpfd != -1) 21 | { 22 | close(mEpfd); 23 | } 24 | } 25 | 26 | int EpollPoller::processPendingEvents(double maxWait) 27 | { 28 | const int MAX_EVENTS = 10; 29 | struct epoll_event events[MAX_EVENTS]; 30 | int maxWaitInMilliseconds = int(ceil(maxWait * 1000)); 31 | 32 | uint64 startTime = getTimeStamp(); 33 | int nfds = epoll_wait(mEpfd, events, MAX_EVENTS, maxWaitInMilliseconds); 34 | mSpareTime += getTimeStamp() - startTime; 35 | 36 | for (int i = 0; i < nfds; ++i) 37 | { 38 | if (events[i].events & (EPOLLERR|EPOLLHUP)) 39 | { 40 | this->triggerError(events[i].data.fd); 41 | } 42 | else 43 | { 44 | if (events[i].events & EPOLLIN) 45 | { 46 | this->triggerRead(events[i].data.fd); 47 | } 48 | 49 | if (events[i].events & EPOLLOUT) 50 | { 51 | this->triggerWrite(events[i].data.fd); 52 | } 53 | } 54 | } 55 | 56 | return nfds; 57 | } 58 | 59 | bool EpollPoller::doRegister(int fd, bool isRead, bool isRegister) 60 | { 61 | struct epoll_event ev; 62 | memset(&ev, 0, sizeof(ev)); 63 | ev.data.fd = fd; 64 | 65 | int op; 66 | if (this->isRegistered(fd, !isRead)) 67 | { 68 | op = EPOLL_CTL_MOD; 69 | ev.events = isRegister ? (EPOLLIN | EPOLLOUT) : (isRead ? EPOLLOUT : EPOLLIN); 70 | } 71 | else 72 | { 73 | op = isRegister ? EPOLL_CTL_ADD : EPOLL_CTL_DEL; 74 | ev.events = isRead ? EPOLLIN : EPOLLOUT; 75 | } 76 | 77 | if (epoll_ctl(mEpfd, op, fd, &ev) < 0) 78 | { 79 | char errMsg[MAX_BUF] = {0}; 80 | snprintf(errMsg, sizeof(errMsg), 81 | "EpollPoller::doRegister() Failed to %s %s file descriptor %d (%s)", 82 | (isRegister ? "add" : "remove"), 83 | (isRead ? "read" : "write"), 84 | fd, 85 | coreStrError()); 86 | ErrorPrint(errMsg); 87 | 88 | return false; 89 | } 90 | 91 | return true; 92 | } 93 | 94 | NAMESPACE_END // namespace tun 95 | 96 | #endif // HAS_EPOLL 97 | -------------------------------------------------------------------------------- /script/tun-cli: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #==================================================================== 3 | # Run level information: 4 | # chkconfig: 345 99 99 5 | # Description: fast tunnel client 6 | # processname: tun-cli 7 | #==================================================================== 8 | 9 | 10 | #==================================================================== 11 | # Configuration 12 | 13 | # Source function library 14 | . /etc/rc.d/init.d/functions 15 | 16 | # Check that networking is up. 17 | [ ${NETWORKING} ="yes" ] || exit 0 18 | 19 | # Daemon 20 | NAME=tun-cli 21 | DAEMON=/usr/local/bin/tun-cli 22 | CONF=/etc/fast-tun.ini 23 | 24 | #USER="nobody" 25 | #GROUP="nobody" 26 | 27 | # Take care of pidfile permissions 28 | mkdir /var/run/$NAME 2>/dev/null || true 29 | #chown "$USER:$GROUP" /var/run/$NAME 30 | 31 | # Check the configuration file exists. 32 | if [ ! -f $CONF ] ; then 33 | echo "The configuration file cannot be found!" 34 | exit 0 35 | fi 36 | 37 | # Path to the lock file. 38 | LOCK_FILE=/var/lock/subsys/$NAME 39 | 40 | # Path to the pid file. 41 | PID=/var/run/$NAME/pid 42 | #==================================================================== 43 | 44 | 45 | #==================================================================== 46 | # Run controls: 47 | 48 | RETVAL=0 49 | 50 | # Start shadowsocks as daemon. 51 | # 52 | start() { 53 | if [ -f $LOCK_FILE ]; then 54 | echo "$NAME is already running!" 55 | exit 0 56 | else 57 | echo -n $"Starting ${NAME}: " 58 | #daemon --check $DAEMON --user $USER "$DAEMON -f $PID -c $CONF > /dev/null" 59 | daemon $DAEMON -c $CONF -f $PID -v 60 | fi 61 | 62 | RETVAL=$? 63 | [ $RETVAL -eq 0 ] && success 64 | echo 65 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE 66 | return $RETVAL 67 | } 68 | 69 | # Stop shadowsocks. 70 | # 71 | stop() { 72 | echo -n $"Shutting down ${NAME}: " 73 | killproc -p ${PID} 74 | RETVAL=$? 75 | [ $RETVAL -eq 0 ] 76 | rm -f $LOCK_FILE 77 | rm -f ${PID} 78 | echo 79 | return $RETVAL 80 | } 81 | 82 | # See how we were called. 83 | case "$1" in 84 | start) 85 | start;; 86 | stop) 87 | stop;; 88 | restart) 89 | stop 90 | start 91 | ;; 92 | condrestart) 93 | if [ -f $LOCK_FILE ]; then 94 | stop 95 | start 96 | RETVAL=$? 97 | fi 98 | ;; 99 | status) 100 | status $DAEMON 101 | RETVAL=$? 102 | ;; 103 | *) 104 | echo $"Usage: $0 {start|stop|restart|condrestart|status}" 105 | RETVAL=1 106 | esac 107 | 108 | exit $RETVAL 109 | #==================================================================== 110 | -------------------------------------------------------------------------------- /script/tun-svr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #==================================================================== 3 | # Run level information: 4 | # chkconfig: 345 99 99 5 | # Description: fast tunnel server 6 | # processname: tun-svr 7 | #==================================================================== 8 | 9 | 10 | #==================================================================== 11 | # Configuration 12 | 13 | # Source function library 14 | . /etc/rc.d/init.d/functions 15 | 16 | # Check that networking is up. 17 | [ ${NETWORKING} ="yes" ] || exit 0 18 | 19 | # Daemon 20 | NAME=tun-svr 21 | DAEMON=/usr/local/bin/tun-svr 22 | CONF=/etc/fast-tun.ini 23 | 24 | #USER="nobody" 25 | #GROUP="nobody" 26 | 27 | # Take care of pidfile permissions 28 | mkdir /var/run/$NAME 2>/dev/null || true 29 | #chown "$USER:$GROUP" /var/run/$NAME 30 | 31 | # Check the configuration file exists. 32 | if [ ! -f $CONF ] ; then 33 | echo "The configuration file cannot be found!" 34 | exit 0 35 | fi 36 | 37 | # Path to the lock file. 38 | LOCK_FILE=/var/lock/subsys/$NAME 39 | 40 | # Path to the pid file. 41 | PID=/var/run/$NAME/pid 42 | #==================================================================== 43 | 44 | 45 | #==================================================================== 46 | # Run controls: 47 | 48 | RETVAL=0 49 | 50 | # Start shadowsocks as daemon. 51 | # 52 | start() { 53 | if [ -f $LOCK_FILE ]; then 54 | echo "$NAME is already running!" 55 | exit 0 56 | else 57 | echo -n $"Starting ${NAME}: " 58 | #daemon --check $DAEMON --user $USER "$DAEMON -f $PID -c $CONF > /dev/null" 59 | daemon $DAEMON -c $CONF -f $PID -v 60 | fi 61 | 62 | RETVAL=$? 63 | [ $RETVAL -eq 0 ] && success 64 | echo 65 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE 66 | return $RETVAL 67 | } 68 | 69 | # Stop shadowsocks. 70 | # 71 | stop() { 72 | echo -n $"Shutting down ${NAME}: " 73 | killproc -p ${PID} 74 | RETVAL=$? 75 | [ $RETVAL -eq 0 ] 76 | rm -f $LOCK_FILE 77 | rm -f ${PID} 78 | echo 79 | return $RETVAL 80 | } 81 | 82 | # See how we were called. 83 | case "$1" in 84 | start) 85 | start;; 86 | stop) 87 | stop;; 88 | restart) 89 | stop 90 | start 91 | ;; 92 | condrestart) 93 | if [ -f $LOCK_FILE ]; then 94 | stop 95 | start 96 | RETVAL=$? 97 | fi 98 | ;; 99 | status) 100 | status $DAEMON 101 | RETVAL=$? 102 | ;; 103 | *) 104 | echo $"Usage: $0 {start|stop|restart|condrestart|status}" 105 | RETVAL=1 106 | esac 107 | 108 | exit $RETVAL 109 | #==================================================================== 110 | -------------------------------------------------------------------------------- /misc/ss-local: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to run Shadowsocks in daemon mode at boot time. 4 | # ScriptAuthor: icyboy 5 | # Revision 1.0 - 14th Sep 2013 6 | #==================================================================== 7 | # Run level information: 8 | # chkconfig: 2345 99 99 9 | # Description: lightweight secured scoks5 proxy 10 | # processname: ss-server 11 | # Author: Max Lv ; 12 | # Run "/sbin/chkconfig --add shadowsocks" to add the Run levels. 13 | #==================================================================== 14 | 15 | #==================================================================== 16 | # Paths and variables and system checks. 17 | 18 | # Source function library 19 | . /etc/rc.d/init.d/functions 20 | 21 | # Check that networking is up. 22 | # 23 | [ ${NETWORKING} ="yes" ] || exit 0 24 | 25 | # Daemon 26 | NAME=ss-local 27 | DAEMON=/usr/local/bin/ss-local 28 | CONF=/etc/ss/ss-local.json 29 | 30 | #USER="nobody" 31 | #GROUP="nobody" 32 | 33 | # Take care of pidfile permissions 34 | mkdir /var/run/$NAME 2>/dev/null || true 35 | #chown "$USER:$GROUP" /var/run/$NAME 36 | 37 | # Check the configuration file exists. 38 | # 39 | if [ ! -f $CONF ] ; then 40 | echo "The configuration file cannot be found!" 41 | exit 0 42 | fi 43 | 44 | # Path to the lock file. 45 | # 46 | LOCK_FILE=/var/lock/subsys/$NAME 47 | 48 | # Path to the pid file. 49 | # 50 | PID=/var/run/$NAME/pid 51 | 52 | 53 | #==================================================================== 54 | 55 | #==================================================================== 56 | # Run controls: 57 | 58 | RETVAL=0 59 | 60 | # Start shadowsocks as daemon. 61 | # 62 | start() { 63 | if [ -f $LOCK_FILE ]; then 64 | echo "$NAME is already running!" 65 | exit 0 66 | else 67 | echo -n $"Starting ${NAME}: " 68 | #daemon --check $DAEMON --user $USER "$DAEMON -f $PID -c $CONF > /dev/null" 69 | daemon $DAEMON -c $CONF -f $PID 70 | fi 71 | 72 | RETVAL=$? 73 | [ $RETVAL -eq 0 ] && success 74 | echo 75 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE 76 | return $RETVAL 77 | } 78 | 79 | 80 | # Stop shadowsocks. 81 | # 82 | stop() { 83 | echo -n $"Shutting down ${NAME}: " 84 | killproc -p ${PID} 85 | RETVAL=$? 86 | [ $RETVAL -eq 0 ] 87 | rm -f $LOCK_FILE 88 | rm -f ${PID} 89 | echo 90 | return $RETVAL 91 | } 92 | 93 | # See how we were called. 94 | case "$1" in 95 | start) 96 | start;; 97 | stop) 98 | stop;; 99 | restart) 100 | stop 101 | start 102 | ;; 103 | condrestart) 104 | if [ -f $LOCK_FILE ]; then 105 | stop 106 | start 107 | RETVAL=$? 108 | fi 109 | ;; 110 | status) 111 | status $DAEMON 112 | RETVAL=$? 113 | ;; 114 | *) 115 | echo $"Usage: $0 {start|stop|restart|condrestart|status}" 116 | RETVAL=1 117 | esac 118 | 119 | exit $RETVAL 120 | -------------------------------------------------------------------------------- /misc/ss-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to run Shadowsocks in daemon mode at boot time. 4 | # ScriptAuthor: icyboy 5 | # Revision 1.0 - 14th Sep 2013 6 | #==================================================================== 7 | # Run level information: 8 | # chkconfig: 2345 99 99 9 | # Description: lightweight secured scoks5 proxy 10 | # processname: ss-server 11 | # Author: Max Lv ; 12 | # Run "/sbin/chkconfig --add shadowsocks" to add the Run levels. 13 | #==================================================================== 14 | 15 | #==================================================================== 16 | # Paths and variables and system checks. 17 | 18 | # Source function library 19 | . /etc/rc.d/init.d/functions 20 | 21 | # Check that networking is up. 22 | # 23 | [ ${NETWORKING} ="yes" ] || exit 0 24 | 25 | # Daemon 26 | NAME=ss-server 27 | DAEMON=/usr/local/bin/ss-server 28 | CONF=/etc/ss/ss-server.json 29 | 30 | #USER="nobody" 31 | #GROUP="nobody" 32 | 33 | # Take care of pidfile permissions 34 | mkdir /var/run/$NAME 2>/dev/null || true 35 | #chown "$USER:$GROUP" /var/run/$NAME 36 | 37 | # Check the configuration file exists. 38 | # 39 | if [ ! -f $CONF ] ; then 40 | echo "The configuration file cannot be found!" 41 | exit 0 42 | fi 43 | 44 | # Path to the lock file. 45 | # 46 | LOCK_FILE=/var/lock/subsys/$NAME 47 | 48 | # Path to the pid file. 49 | # 50 | PID=/var/run/$NAME/pid 51 | 52 | 53 | #==================================================================== 54 | 55 | #==================================================================== 56 | # Run controls: 57 | 58 | RETVAL=0 59 | 60 | # Start shadowsocks as daemon. 61 | # 62 | start() { 63 | if [ -f $LOCK_FILE ]; then 64 | echo "$NAME is already running!" 65 | exit 0 66 | else 67 | echo -n $"Starting ${NAME}: " 68 | #daemon --check $DAEMON --user $USER "$DAEMON -f $PID -c $CONF > /dev/null" 69 | daemon $DAEMON -c $CONF -f $PID 70 | fi 71 | 72 | RETVAL=$? 73 | [ $RETVAL -eq 0 ] && success 74 | echo 75 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE 76 | return $RETVAL 77 | } 78 | 79 | 80 | # Stop shadowsocks. 81 | # 82 | stop() { 83 | echo -n $"Shutting down ${NAME}: " 84 | killproc -p ${PID} 85 | RETVAL=$? 86 | [ $RETVAL -eq 0 ] 87 | rm -f $LOCK_FILE 88 | rm -f ${PID} 89 | echo 90 | return $RETVAL 91 | } 92 | 93 | # See how we were called. 94 | case "$1" in 95 | start) 96 | start;; 97 | stop) 98 | stop;; 99 | restart) 100 | stop 101 | start 102 | ;; 103 | condrestart) 104 | if [ -f $LOCK_FILE ]; then 105 | stop 106 | start 107 | RETVAL=$? 108 | fi 109 | ;; 110 | status) 111 | status $DAEMON 112 | RETVAL=$? 113 | ;; 114 | *) 115 | echo $"Usage: $0 {start|stop|restart|condrestart|status}" 116 | RETVAL=1 117 | esac 118 | 119 | exit $RETVAL 120 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC= gcc 2 | CXX= g++ 3 | MAKE= make 4 | 5 | BINDIR:= /usr/local/bin 6 | CILLDIR:= ../cill 7 | ROOT:= .. 8 | 9 | CFLAGS+= -g -Wall -D_USE_KMEM 10 | CXXFLAGS+= -rdynamic -g -Wall -D_USE_KMEM -I $(CILLDIR) -I $(CILLDIR)/kmem 11 | # CXXFLAGS+= -g -Wall -I $(CILLDIR) -I $(CILLDIR)/kmem -I $(ROOT) 12 | 13 | LDFLAGS+= -rdynamic -L $(CILLDIR)/lib -lcill -llog -lkmem -L $(ROOT)/lib -lkcp -lpthread -lrt -lstdc++ 14 | 15 | RM= -rm -rf 16 | 17 | 18 | COMMON_OBJS:= event_poller.o select_poller.o epoll_poller.o connection.o listener.o \ 19 | fast_connection.o fasttun_base.o udppacket_sender.o disk_cache.o 20 | 21 | .PHONY:all test clean install-cli install-svr fake 22 | all:client.out server.out test.out 23 | test:utest.out 24 | 25 | client.out:$(COMMON_OBJS) client.o 26 | $(CXX) -o $@ $^ $(LDFLAGS) 27 | server.out:$(COMMON_OBJS) server.o 28 | $(CXX) -o $@ $^ $(LDFLAGS) 29 | test.out:$(COMMON_OBJS) test.o 30 | $(CXX) -o $@ $^ $(LDFLAGS) 31 | utest.out:$(COMMON_OBJS) utest.o 32 | $(CXX) -o $@ $^ $(LDFLAGS) -lcppunit 33 | 34 | client.o: client.cpp event_poller.h listener.h connection.h kcp_tunnel.h kcp_tunnel.inl udppacket_sender.h fast_connection.h 35 | server.o: server.cpp event_poller.h listener.h connection.h kcp_tunnel.h kcp_tunnel.inl udppacket_sender.h fast_connection.h \ 36 | cache.h disk_cache.h 37 | test.o: test.cpp event_poller.h listener.h connection.h kcp_tunnel.h kcp_tunnel.inl udppacket_sender.h fast_connection.h \ 38 | cache.h disk_cache.h 39 | utest.o: utest.cpp event_poller.h listener.h connection.h kcp_tunnel.h kcp_tunnel.inl udppacket_sender.h fast_connection.h cache.h \ 40 | message_receiver.h disk_cache.h 41 | 42 | fasttun_base.o: fasttun_base.cpp fasttun_base.h 43 | event_poller.o: event_poller.cpp event_poller.h select_poller.h epoll_poller.h fasttun_base.h 44 | select_poller.o: select_poller.cpp select_poller.h event_poller.h fasttun_base.h 45 | epoll_poller.o: epoll_poller.cpp epoll_poller.h event_poller.h fasttun_base.h 46 | listener.o: listener.cpp listener.h event_poller.h fasttun_base.h 47 | connection.o: connection.cpp connection.h event_poller.h fasttun_base.h 48 | fast_connection.o: fast_connection.cpp fast_connection.h event_poller.h kcp_tunnel.h kcp_tunnel.inl udppacket_sender.h connection.h \ 49 | cache.h disk_cache.h fasttun_base.h message_receiver.h 50 | udppacket_sender.o: udppacket_sender.cpp udppacket_sender.h event_poller.h fasttun_base.h 51 | disk_cache.o: disk_cache.cpp disk_cache.h fasttun_base.h 52 | 53 | 54 | install-cli: 55 | cp client.out $(BINDIR)/tun-cli 56 | cp ../script/tun-cli /etc/init.d/ 57 | 58 | install-svr: 59 | cp server.out $(BINDIR)/tun-svr 60 | cp ../script/tun-svr /etc/init.d/ 61 | 62 | uninstall: 63 | -$(RM) $(BINDIR)/tun-cli $(BINDIR)/tun-svr /etc/init.d/tun-cli /etc/init.d/tun-svr 64 | -service tun-cli stop 65 | -service -tun-svr stop 66 | -chkconfig --del tun-cli 67 | -chkconfig --del tun-svr 68 | 69 | 70 | clean: 71 | $(RM) *.o *.out 72 | 73 | fake: 74 | @echo $(COMMON_OBJS) 75 | -------------------------------------------------------------------------------- /src/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONNECTION_H__ 2 | #define __CONNECTION_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "event_poller.h" 6 | 7 | NAMESPACE_BEG(tun) 8 | 9 | class Connection : public InputNotificationHandler, public OutputNotificationHandler 10 | { 11 | public: 12 | class Handler 13 | { 14 | public: 15 | Handler() {} 16 | 17 | virtual void onConnected(Connection *pConn) {} 18 | virtual void onDisconnected(Connection *pConn) {} 19 | 20 | virtual void onRecv(Connection *pConn, const void *data, size_t datalen) = 0; 21 | virtual void onError(Connection *pConn) {} 22 | }; 23 | 24 | enum EConnStatus 25 | { 26 | ConnStatus_Closed, 27 | ConnStatus_Error, 28 | 29 | ConnStatus_Connecting, 30 | ConnStatus_Connected, 31 | }; 32 | 33 | Connection(EventPoller *poller) 34 | :mFd(-1) 35 | ,mConnStatus(ConnStatus_Closed) 36 | ,mHandler(NULL) 37 | ,mEventPoller(poller) 38 | ,mbRegForRead(false) 39 | ,mbRegForWrite(false) 40 | ,mTcpPacketList() 41 | ,mBuffer(NULL) 42 | { 43 | assert(mEventPoller && "Connection::mEventPoller != NULL"); 44 | 45 | mBuffer = (char *)malloc(MAXLEN); 46 | assert(mBuffer != NULL && "Connection malloc buffer failed"); 47 | } 48 | 49 | virtual ~Connection(); 50 | 51 | bool acceptConnection(int connfd); 52 | bool connect(const char *ip, int port); 53 | bool connect(const SA *sa, socklen_t salen); 54 | 55 | void shutdown(); 56 | 57 | void send(const void *data, size_t datalen); 58 | 59 | inline void setEventHandler(Handler *h) 60 | { 61 | mHandler = h; 62 | } 63 | 64 | inline bool isConnected() const 65 | { 66 | return mConnStatus == ConnStatus_Connected; 67 | } 68 | 69 | bool getpeername(SA *sa, socklen_t *salen) const; 70 | bool gethostname(SA *sa, socklen_t *salen) const; 71 | 72 | // InputNotificationHandler 73 | virtual int handleInputNotification(int fd); 74 | 75 | // OutputNotificationHandler 76 | virtual int handleOutputNotification(int fd); 77 | 78 | private: 79 | void tryRegReadEvent(); 80 | void tryUnregReadEvent(); 81 | 82 | void tryRegWriteEvent(); 83 | void tryUnregWriteEvent(); 84 | 85 | bool tryFlushRemainPacket(); 86 | void cachePacket(const void *data, size_t datalen); 87 | 88 | bool checkSocketErrors(); 89 | EReason _checkSocketErrors(); 90 | 91 | private: 92 | static const int MAXLEN = 8*1024; 93 | static const int LIMIT_LEN = 1024*1024; 94 | typedef std::list TcpPacketList; 95 | 96 | int mFd; 97 | EConnStatus mConnStatus; 98 | Handler *mHandler; 99 | 100 | EventPoller *mEventPoller; 101 | bool mbRegForRead; 102 | bool mbRegForWrite; 103 | 104 | TcpPacketList mTcpPacketList; 105 | 106 | char *mBuffer; 107 | }; 108 | 109 | NAMESPACE_END // namespace tun 110 | 111 | #endif // __CONNECTION_H__ 112 | -------------------------------------------------------------------------------- /src/event_poller.cpp: -------------------------------------------------------------------------------- 1 | #include "event_poller.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | EventPoller::EventPoller() 6 | :mSpareTime(0) 7 | ,mFdReadHandlers() 8 | ,mFdWriteHandlers() 9 | { 10 | } 11 | 12 | EventPoller::~EventPoller() 13 | { 14 | } 15 | 16 | bool EventPoller::registerForRead(int fd, InputNotificationHandler *handler) 17 | { 18 | if (!this->doRegisterForRead(fd)) 19 | { 20 | return false; 21 | } 22 | 23 | mFdReadHandlers[fd] = handler; 24 | 25 | return true; 26 | } 27 | 28 | bool EventPoller::registerForWrite(int fd, OutputNotificationHandler *handler) 29 | { 30 | if (!this->doRegisterForWrite(fd)) 31 | { 32 | return false; 33 | } 34 | 35 | mFdWriteHandlers[fd] = handler; 36 | 37 | return true; 38 | } 39 | 40 | bool EventPoller::deregisterForRead(int fd) 41 | { 42 | mFdReadHandlers.erase(fd); 43 | 44 | return this->doDeregisterForRead(fd); 45 | } 46 | 47 | bool EventPoller::deregisterForWrite(int fd) 48 | { 49 | mFdWriteHandlers.erase(fd); 50 | 51 | return this->doDeregisterForWrite(fd); 52 | } 53 | 54 | bool EventPoller::triggerRead(int fd) 55 | { 56 | FDReadHandlers::iterator iter = mFdReadHandlers.find(fd); 57 | 58 | if (iter == mFdReadHandlers.end()) 59 | { 60 | return false; 61 | } 62 | 63 | iter->second->handleInputNotification(fd); 64 | 65 | return true; 66 | } 67 | 68 | bool EventPoller::triggerWrite(int fd) 69 | { 70 | FDWriteHandlers::iterator iter = mFdWriteHandlers.find(fd); 71 | 72 | if (iter == mFdWriteHandlers.end()) 73 | { 74 | return false; 75 | } 76 | 77 | iter->second->handleOutputNotification(fd); 78 | 79 | return true; 80 | } 81 | 82 | bool EventPoller::triggerError(int fd) 83 | { 84 | if (!this->triggerRead(fd)) 85 | { 86 | return this->triggerWrite(fd); 87 | } 88 | 89 | return true; 90 | } 91 | 92 | bool EventPoller::isRegistered(int fd, bool isForRead) const 93 | { 94 | return isForRead ? (mFdReadHandlers.find(fd) != mFdReadHandlers.end()) : 95 | (mFdWriteHandlers.find(fd) != mFdWriteHandlers.end()); 96 | } 97 | 98 | int EventPoller::getFileDescriptor() const 99 | { 100 | return -1; 101 | } 102 | 103 | InputNotificationHandler *EventPoller::findForRead(int fd) 104 | { 105 | FDReadHandlers::iterator iter = mFdReadHandlers.find(fd); 106 | 107 | if(iter == mFdReadHandlers.end()) 108 | return NULL; 109 | 110 | return iter->second; 111 | } 112 | 113 | OutputNotificationHandler *EventPoller::findForWrite(int fd) 114 | { 115 | FDWriteHandlers::iterator iter = mFdWriteHandlers.find(fd); 116 | 117 | if(iter == mFdWriteHandlers.end()) 118 | return NULL; 119 | 120 | return iter->second; 121 | } 122 | 123 | int EventPoller::recalcMaxFD() const 124 | { 125 | int readMaxFD = -1; 126 | 127 | FDReadHandlers::const_iterator readHandlerIter = mFdReadHandlers.begin(); 128 | while (readHandlerIter != mFdReadHandlers.end()) 129 | { 130 | if (readHandlerIter->first > readMaxFD) 131 | { 132 | readMaxFD = readHandlerIter->first; 133 | } 134 | 135 | ++readHandlerIter; 136 | } 137 | 138 | int writeMaxFD = -1; 139 | 140 | FDWriteHandlers::const_iterator writeHanderIter = mFdWriteHandlers.begin(); 141 | while (writeHanderIter != mFdWriteHandlers.end()) 142 | { 143 | if (writeHanderIter->first > writeMaxFD) 144 | { 145 | writeMaxFD = writeHanderIter->first; 146 | } 147 | 148 | ++writeHanderIter; 149 | } 150 | 151 | return max(readMaxFD, writeMaxFD); 152 | } 153 | 154 | NAMESPACE_END // namespace tun 155 | -------------------------------------------------------------------------------- /src/utest.cpp: -------------------------------------------------------------------------------- 1 | #include "utest.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cppunit/extensions/TestFactoryRegistry.h" 8 | #include "cppunit/ui/text/TestRunner.h" 9 | 10 | CPPUNIT_TEST_SUITE_REGISTRATION(UTest); 11 | 12 | using namespace tun; 13 | 14 | UTest::~UTest() 15 | {} 16 | 17 | void UTest::setUp() 18 | {} 19 | 20 | void UTest::tearDown() 21 | {} 22 | 23 | static const int TEST_COUNT = 128; 24 | static uint8* buf[TEST_COUNT]; 25 | static uint16 buflen[TEST_COUNT]; 26 | typedef msg::MessageReceiver MsgReceiver; 27 | void UTest::testMessageReceiver() 28 | { 29 | MsgReceiver *msgrcv = new MsgReceiver(this, &UTest::_onRecvMessage, &UTest::_onRecvMsgError); 30 | 31 | for (int i = 0; i < TEST_COUNT; ++i) 32 | { 33 | buflen[i] = random() % 65535; 34 | if (buflen[i] == 0) 35 | buflen[i] = 1; 36 | 37 | buf[i] = (uint8*)malloc(buflen[i]); 38 | for (int j = 0; j < buflen[i]; ++j) 39 | { 40 | buf[i][j] = (i+j)%256; 41 | } 42 | 43 | uint16 len = sizeof(int)+buflen[i]; 44 | MemoryStream header; 45 | header< header.length()) 53 | randlen = header.length()-k; 54 | msgrcv->input(header.data()+k, randlen, NULL); 55 | k += randlen; 56 | } 57 | k = 0; 58 | while (k < buflen[i]) 59 | { 60 | uint16 randlen = random()%1000; 61 | if (k+randlen > buflen[i]) 62 | randlen = buflen[i]-k; 63 | msgrcv->input(buf[i]+k, randlen, NULL); 64 | k += randlen; 65 | } 66 | } 67 | } 68 | 69 | void UTest::_onRecvMessage(const void *data, uint16 datalen, void *) 70 | { 71 | CPPUNIT_ASSERT(datalen >= sizeof(int)); 72 | 73 | const char *ptr = (const char *)data; 74 | MemoryStream header; 75 | 76 | header.append(ptr, sizeof(int)); 77 | ptr += sizeof(int); 78 | datalen -= sizeof(int); 79 | 80 | int index = -1; 81 | header>>index; 82 | CPPUNIT_ASSERT(index >= 0); 83 | CPPUNIT_ASSERT(buflen[index] == datalen); 84 | CPPUNIT_ASSERT(memcmp(ptr, buf[index], datalen) == 0); 85 | } 86 | 87 | void UTest::_onRecvMsgError(void *) 88 | { 89 | CPPUNIT_ASSERT(false); 90 | } 91 | 92 | void UTest::testDiskCache() 93 | { 94 | const char *strs[] = { 95 | "test1", 96 | "test23", 97 | "fkadsfkjsdakfjasdjfkasjrieuwqrnkvnakfhijlkf5a4s5f74asf42asd1fasdf", 98 | "jfakdsiofruewiorewnckjdkfjasfjdnafkmnmnkjujwiue9q k safjkdsajfkmmjjlklk", 99 | }; 100 | 101 | DiskCache c; 102 | for (int i = 0; i < sizeof(strs)/sizeof(const char *); ++i) 103 | { 104 | c.write(strs[i], strlen(strs[i])); 105 | } 106 | 107 | char *ptr = NULL; 108 | ssize_t sz = 0; 109 | int i = 0; 110 | while ((sz = c.peeksize()) > 0) 111 | { 112 | ptr = (char *)malloc(sz); 113 | c.read(ptr, sz); 114 | CPPUNIT_ASSERT(memcmp(ptr, strs[i++], sz) == 0); 115 | } 116 | } 117 | 118 | 119 | int main(int argc, char *argv[]) 120 | { 121 | core::createTrace(); 122 | // core::output2Console(); 123 | core::output2File("utest.log"); 124 | 125 | CppUnit::TextUi::TestRunner runner; 126 | runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); 127 | runner.run(); 128 | 129 | core::closeTrace(); 130 | // getchar(); 131 | exit(0); 132 | } 133 | -------------------------------------------------------------------------------- /src/fast_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef __FASTCONNECTION_H__ 2 | #define __FASTCONNECTION_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "event_poller.h" 6 | #include "kcp_tunnel.h" 7 | #include "connection.h" 8 | #include "cache.h" 9 | #include "message_receiver.h" 10 | 11 | NAMESPACE_BEG(tun) 12 | 13 | class FastConnection : public Connection::Handler, public KcpTunnelHandler 14 | { 15 | public: 16 | class Handler 17 | { 18 | public: 19 | Handler() {} 20 | 21 | virtual void onConnected(FastConnection *pConn) {} 22 | virtual void onDisconnected(FastConnection *pConn) {} 23 | virtual void onError(FastConnection *pConn) {} 24 | 25 | virtual void onCreateKcpTunnelFailed(FastConnection *pConn) {} 26 | 27 | virtual void onRecv(FastConnection *pConn, const void *data, size_t datalen) {} 28 | }; 29 | 30 | FastConnection(EventPoller *poller, ITunnelGroup *pGroup) 31 | :mEventPoller(poller) 32 | ,mpTunnelGroup(pGroup) 33 | ,mpConnection(NULL) 34 | ,mpKcpTunnel(NULL) 35 | ,mbTunnelConnected(false) 36 | ,mpHandler(NULL) 37 | ,mCache(NULL) 38 | ,mMsgRcv(NULL) 39 | ,mHeartBeatRecord() 40 | { 41 | mCache = new MyCache(this, &FastConnection::flush); 42 | mMsgRcv = new MsgRcv(this, &FastConnection::onRecvMsg, &FastConnection::onRecvMsgErr); 43 | } 44 | 45 | virtual ~FastConnection(); 46 | 47 | bool acceptConnection(int connfd); 48 | bool connect(const char *ip, int port); 49 | bool connect(const SA *sa, socklen_t salen); 50 | 51 | void shutdown(); 52 | 53 | int send(const void *data, size_t datalen); 54 | void _flushAll(); 55 | bool flush(const void *data, size_t datalen); 56 | 57 | void triggerHeartBeatPacket(); 58 | const HeartBeatRecord& getHeartBeatRecord() const; 59 | 60 | // Connection::Handler 61 | virtual void onConnected(Connection *pConn); 62 | virtual void onDisconnected(Connection *pConn); 63 | 64 | virtual void onRecv(Connection *pConn, const void *data, size_t datalen); 65 | virtual void onError(Connection *pConn); 66 | 67 | // KcpTunnel::Handler 68 | virtual void onRecv(const void *data, size_t datalen); 69 | 70 | inline void setEventHandler(Handler *h) 71 | { 72 | mpHandler = h; 73 | } 74 | 75 | inline Connection* getConnection() const 76 | { 77 | return mpConnection; 78 | } 79 | 80 | inline ITunnel* getKcpTunnel() const 81 | { 82 | return mpKcpTunnel; 83 | } 84 | 85 | inline bool isConnected() const 86 | { 87 | if (mpConnection) 88 | return mpConnection->isConnected(); 89 | return false; 90 | } 91 | 92 | private: 93 | void onRecvMsg(const void *data, uint8 datalen, void *user); 94 | void onRecvMsgErr(void *user); 95 | 96 | void sendMessage(int msgid, const void *data, size_t datalen); 97 | 98 | private: 99 | enum 100 | { 101 | MsgId_CreateKcpTunnel = 0, 102 | MsgId_ConfirmCreateKcpTunnel, 103 | MsgId_HeartBeat_Request, 104 | MsgId_HeartBeat_Response, 105 | }; 106 | 107 | typedef Cache MyCache; 108 | typedef msg::MessageReceiver MsgRcv; 109 | 110 | EventPoller *mEventPoller; 111 | ITunnelGroup *mpTunnelGroup; 112 | 113 | Connection *mpConnection; 114 | ITunnel *mpKcpTunnel; 115 | bool mbTunnelConnected; 116 | 117 | Handler *mpHandler; 118 | 119 | MyCache *mCache; 120 | 121 | MsgRcv *mMsgRcv; 122 | 123 | HeartBeatRecord mHeartBeatRecord; 124 | }; 125 | 126 | NAMESPACE_END // namespace tun 127 | 128 | #endif // __FASTCONNECTION_H__ 129 | -------------------------------------------------------------------------------- /src/cache.h: -------------------------------------------------------------------------------- 1 | #ifndef __CACHE_H__ 2 | #define __CACHE_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "disk_cache.h" 6 | 7 | NAMESPACE_BEG(tun) 8 | 9 | template 10 | class Cache 11 | { 12 | typedef bool (T::*FuncType)(const void *, size_t); 13 | public: 14 | Cache(T *host, FuncType func) 15 | :mHost(host) 16 | ,mFunc(func) 17 | ,mCachedList() 18 | ,mDiskCache() 19 | ,mLenCacheInMem(0) 20 | ,mLenCacheInFile(0) 21 | {} 22 | 23 | virtual ~Cache() 24 | { 25 | typename DataList::iterator it = this->mCachedList.begin(); 26 | for (; it != this->mCachedList.end(); ++it) 27 | { 28 | free((*it).data); 29 | } 30 | this->mCachedList.clear(); 31 | } 32 | 33 | bool empty() const 34 | { 35 | return 0 == mLenCacheInMem && 0 == mLenCacheInFile; 36 | } 37 | 38 | void cache(const void *data, size_t len) 39 | { 40 | assert(len > 0 && "cache() && len>0"); 41 | 42 | // cache in file 43 | if (mLenCacheInMem+len > MAX_LEN_CACHE_IN_MEM || mLenCacheInFile > 0) 44 | { 45 | int ret = mDiskCache.write(data, len); 46 | if (ret == (int)len) 47 | { 48 | mLenCacheInFile += len; 49 | return; 50 | } 51 | 52 | ErrorPrint("Cache::cache() write to file failed! return code:%d", ret); 53 | } 54 | 55 | // cache in mem 56 | Data d; 57 | mLenCacheInMem += len; 58 | d.len = len; 59 | d.data = (char *)malloc(len); 60 | assert(d.data != NULL && "cache() malloc failed"); 61 | memcpy(d.data, data, len); 62 | this->mCachedList.push_back(d); 63 | } 64 | 65 | void clear() 66 | { 67 | typename DataList::iterator it = this->mCachedList.begin(); 68 | for (; it != this->mCachedList.end(); ++it) 69 | { 70 | free((*it).data); 71 | } 72 | this->mCachedList.clear(); 73 | 74 | mDiskCache.clear(); 75 | } 76 | 77 | bool flushAll() 78 | { 79 | typename DataList::iterator it = this->mCachedList.begin(); 80 | for (; it != this->mCachedList.end(); ) 81 | { 82 | if ((mHost->*mFunc)((*it).data, (*it).len)) 83 | { 84 | mLenCacheInMem -= (*it).len; 85 | free((*it).data); 86 | mCachedList.erase(it++); 87 | } 88 | else 89 | { 90 | return false; 91 | } 92 | } 93 | 94 | for (ssize_t sz = mDiskCache.peeksize(); sz > 0; sz = mDiskCache.peeksize()) 95 | { 96 | char *ptr = (char *)malloc(sz); 97 | if (NULL == ptr) 98 | { 99 | ErrorPrint("malloc failed size=%lld", sz); 100 | assert(false); 101 | } 102 | assert(mDiskCache.read(ptr, sz) == sz); 103 | 104 | if ((mHost->*mFunc)(ptr, sz)) 105 | { 106 | mLenCacheInFile -= sz; 107 | free(ptr); 108 | } 109 | else 110 | { 111 | free(ptr); 112 | mDiskCache.rollback(sz); 113 | return false; 114 | } 115 | } 116 | 117 | return true; 118 | } 119 | 120 | private: 121 | struct Data 122 | { 123 | size_t len; 124 | char *data; 125 | }; 126 | 127 | typedef std::list DataList; 128 | 129 | T *mHost; 130 | FuncType mFunc; 131 | DataList mCachedList; 132 | DiskCache mDiskCache; 133 | size_t mLenCacheInMem; 134 | size_t mLenCacheInFile; 135 | }; 136 | 137 | NAMESPACE_END // namespace tun 138 | 139 | #endif // __CACHE_H__ 140 | -------------------------------------------------------------------------------- /src/listener.cpp: -------------------------------------------------------------------------------- 1 | #include "listener.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | Listener::~Listener() 6 | { 7 | finalise(); 8 | } 9 | 10 | bool Listener::initialise(const char *ip, int port) 11 | { 12 | struct sockaddr_in remoteAddr; 13 | remoteAddr.sin_family = AF_INET; 14 | remoteAddr.sin_port = htons(port); 15 | if (inet_pton(AF_INET, ip, &remoteAddr.sin_addr) < 0) 16 | { 17 | ErrorPrint("[Listener::initialise] illegal ip(%s)", ip); 18 | return false; 19 | } 20 | 21 | return initialise((const SA *)&remoteAddr, sizeof(remoteAddr)); 22 | } 23 | 24 | bool Listener::initialise(const SA *sa, socklen_t salen) 25 | { 26 | if (mFd >= 0) 27 | { 28 | ErrorPrint("Listener already inited!"); 29 | return false; 30 | } 31 | 32 | mFd = socket(AF_INET, SOCK_STREAM, 0); 33 | if (mFd < 0) 34 | { 35 | ErrorPrint("[Listener::initialise] init socket error! %s", coreStrError()); 36 | return false; 37 | } 38 | 39 | int opt = 1; 40 | setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 41 | 42 | #ifdef SO_REUSEPORT 43 | opt = 1; 44 | setsockopt(mFd, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt, sizeof(opt)); 45 | #endif 46 | 47 | // set nonblocking 48 | if (!core::setNonblocking(mFd)) 49 | { 50 | ErrorPrint("[Listener::initialise] set nonblocking error! %s", coreStrError()); 51 | goto err_1; 52 | } 53 | 54 | if (bind(mFd, sa, salen) < 0) 55 | { 56 | ErrorPrint("[Listener::initialise] bind error! %s", coreStrError()); 57 | goto err_1; 58 | } 59 | 60 | if (listen(mFd, LISTENQ) < 0) 61 | { 62 | ErrorPrint("[Listener::initialise] listen failed! %s", coreStrError()); 63 | goto err_1; 64 | } 65 | 66 | if (!mEventPoller->registerForRead(mFd, this)) 67 | { 68 | ErrorPrint("[Listener::initialise] registerForRead failed! %s", coreStrError()); 69 | goto err_1; 70 | } 71 | 72 | return true; 73 | 74 | err_1: 75 | close(mFd); 76 | mFd = -1; 77 | 78 | return false; 79 | } 80 | 81 | void Listener::finalise() 82 | { 83 | if (mFd < 0) 84 | return; 85 | 86 | mEventPoller->deregisterForRead(mFd); 87 | close(mFd); 88 | mFd = -1; 89 | } 90 | 91 | int Listener::handleInputNotification(int fd) 92 | { 93 | struct sockaddr_in addr; 94 | socklen_t addrlen; 95 | int newConns = 0; 96 | while (newConns++ < 32) 97 | { 98 | addrlen = sizeof(addr); 99 | int connfd = accept(fd, (SA *)&addr, &addrlen); 100 | if (connfd < 0) 101 | { 102 | // DebugPrint("accept failed! %s", coreStrError()); 103 | break; 104 | } 105 | else 106 | { 107 | #if 0 108 | struct sockaddr_in localAddr, remoteAddr; 109 | socklen_t localAddrLen = sizeof(localAddr), remoteAddrLen = sizeof(remoteAddr); 110 | if (getsockname(connfd, (SA *)&localAddr, &localAddrLen) == 0 && 111 | getpeername(connfd, (SA *)&remoteAddr, &remoteAddrLen) == 0) 112 | { 113 | char remoteip[MAX_BUF] = {0}, localip[MAX_BUF] = {0}; 114 | if (inet_ntop(AF_INET, &localAddr.sin_addr, localip, sizeof(localip)) && 115 | inet_ntop(AF_INET, &remoteAddr.sin_addr, remoteip, sizeof(remoteip))) 116 | { 117 | char acceptLog[1024] = {0}; 118 | snprintf(acceptLog, sizeof(acceptLog), "(%s:%d) accept from %s:%d", 119 | localip, ntohs(localAddr.sin_port), 120 | remoteip, ntohs(remoteAddr.sin_port)); 121 | DebugPrint(acceptLog); 122 | } 123 | } 124 | #endif 125 | 126 | if (mHandler) 127 | { 128 | mHandler->onAccept(connfd); 129 | } 130 | } 131 | } 132 | 133 | return 0; 134 | } 135 | 136 | NAMESPACE_END // namespace tun 137 | -------------------------------------------------------------------------------- /src/fasttun_base.h: -------------------------------------------------------------------------------- 1 | #ifndef __FASTTUNBASE_H__ 2 | #define __FASTTUNBASE_H__ 3 | 4 | #include "core/cillcore.h" 5 | #include 6 | 7 | using core::mchar; 8 | using core::wchar; 9 | 10 | using core::tchar; 11 | using core::tstring; 12 | 13 | using core::uchar; 14 | using core::ushort; 15 | using core::uint; 16 | using core::ulong; 17 | 18 | using core::int64; 19 | using core::int32; 20 | using core::int16; 21 | using core::int8; 22 | using core::uint64; 23 | using core::uint32; 24 | using core::uint16; 25 | using core::uint8; 26 | using core::intptr; 27 | using core::uintptr; 28 | 29 | using core::MemoryStream; 30 | 31 | using core::getTimeStamp; 32 | using core::coreStrError; 33 | using core::Ini; 34 | using core::TimerHandler; 35 | using core::TimerHandle; 36 | 37 | typedef struct sockaddr SA; 38 | 39 | #define GLOBAL_TUN_ID 100 40 | #define LISTENQ 32 41 | #define DEFAULT_CONF_PATH "/etc/fasttun/config.ini" 42 | 43 | NAMESPACE_BEG(tun) 44 | 45 | //-------------------------------------------------------------------------- 46 | enum EReason 47 | { 48 | Reason_Success = 0, 49 | 50 | Reason_TimerExpired = -1, 51 | Reason_NoSuchPort = -2, 52 | Reason_GeneralNetwork = -3, 53 | Reason_CorruptedPacket = -4, 54 | Reason_NonExistentEntry = -5, 55 | Reason_WindowOverflow = -6, 56 | Reason_Inactivity = -7, 57 | Reason_ResourceUnavailable = -8, 58 | Reason_ClientDisconnected = -9, 59 | Reason_TransmitQueueFull = -10, 60 | Reason_ShuttingDown = -11, 61 | Reason_WebSocketError = -12, 62 | }; 63 | //-------------------------------------------------------------------------- 64 | 65 | //-------------------------------------------------------------------------- 66 | struct Packet 67 | { 68 | char *buf; 69 | size_t buflen; 70 | 71 | Packet() : buf(NULL), buflen(0) 72 | { 73 | } 74 | 75 | virtual ~Packet() 76 | { 77 | if (buf) 78 | free(buf); 79 | } 80 | }; 81 | 82 | struct TcpPacket : public Packet 83 | { 84 | size_t sentlen; 85 | 86 | TcpPacket() : Packet(), sentlen(0) 87 | { 88 | } 89 | 90 | virtual ~TcpPacket() 91 | { 92 | } 93 | }; 94 | //-------------------------------------------------------------------------- 95 | 96 | //-------------------------------------------------------------------------- 97 | // ID Generator 98 | template 99 | class IDGenerator 100 | { 101 | public: 102 | bool genNewId(T& r) 103 | { 104 | if (mAvailableIds.empty()) 105 | { 106 | return false; 107 | } 108 | 109 | r = mAvailableIds.front(); 110 | mAvailableIds.pop_front(); 111 | return true; 112 | } 113 | 114 | void restorId(const T &r) 115 | { 116 | mAvailableIds.push_back(r); 117 | } 118 | 119 | protected: 120 | IDGenerator() {} 121 | virtual ~IDGenerator() {} 122 | 123 | protected: 124 | typedef std::list IDList; 125 | 126 | IDList mAvailableIds; 127 | }; 128 | //-------------------------------------------------------------------------- 129 | 130 | //-------------------------------------------------------------------------- 131 | struct HeartBeatRecord 132 | { 133 | uint32 packetSentTime, packetRecvTime; 134 | 135 | static const uint32 HEARTBEAT_INTERVAL = 30000; 136 | static const uint32 CONNTIMEOUT_TIME = HEARTBEAT_INTERVAL*4; 137 | 138 | HeartBeatRecord() 139 | :packetSentTime(0) 140 | ,packetRecvTime(0) 141 | {} 142 | 143 | bool isTimeout() const 144 | { 145 | uint32 curClock = core::getClock(); 146 | if (curClock >= packetSentTime && 147 | curClock >= packetRecvTime && 148 | curClock-packetSentTime <= HEARTBEAT_INTERVAL*2 && 149 | packetRecvTime > 0 && curClock-packetRecvTime >= CONNTIMEOUT_TIME) 150 | { 151 | return true; 152 | } 153 | return false; 154 | } 155 | }; 156 | //-------------------------------------------------------------------------- 157 | 158 | extern core::Timers gTimer; 159 | 160 | void daemonize(const char *path); 161 | void print_stack_frames(); 162 | 163 | NAMESPACE_END // namespace tun 164 | 165 | #endif // __FASTTUNBASE_H__ 166 | -------------------------------------------------------------------------------- /src/select_poller.cpp: -------------------------------------------------------------------------------- 1 | #include "select_poller.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | SelectPoller::SelectPoller() 6 | :EventPoller() 7 | ,mMaxFd(-1) 8 | ,mFdWriteCount(0) 9 | { 10 | FD_ZERO(&mFdReadSet); 11 | FD_ZERO(&mFdWriteSet); 12 | } 13 | 14 | int SelectPoller::processPendingEvents(double maxWait) 15 | { 16 | fd_set readFDs; 17 | fd_set writeFDs; 18 | struct timeval nextTimeout; 19 | 20 | FD_ZERO(&readFDs); 21 | FD_ZERO(&writeFDs); 22 | 23 | readFDs = mFdReadSet; 24 | writeFDs = mFdWriteSet; 25 | 26 | nextTimeout.tv_sec = (int)maxWait; 27 | nextTimeout.tv_usec = (int)((maxWait - (double)nextTimeout.tv_sec) * 1000000.0); 28 | 29 | uint64 startTime = getTimeStamp(); 30 | int countReady = 0; 31 | 32 | #ifdef _WIN32 33 | if (mMaxFd == -1) 34 | { 35 | Sleep(int(maxWait * 1000.0)); 36 | } 37 | else 38 | #endif 39 | { 40 | countReady = select(mMaxFd+1, &readFDs, mFdWriteCount ? &writeFDs : NULL, NULL, &nextTimeout); 41 | } 42 | 43 | mSpareTime += getTimeStamp() - startTime; 44 | 45 | if (countReady > 0) 46 | { 47 | this->handleNotifications(countReady, readFDs, writeFDs); 48 | } 49 | else if (countReady == -1) 50 | { 51 | WarningPrint("EventDispatcher::processPendingEvents() error in select() err:%s", coreStrError()); 52 | } 53 | 54 | return countReady; 55 | } 56 | 57 | void SelectPoller::handleNotifications(int &countReady, fd_set &readFDs, fd_set &writeFDs) 58 | { 59 | #ifdef _WIN32 60 | for (unsigned i = 0; i < readFDs.fd_count; ++i) 61 | { 62 | int fd = readFDs.fd_array[i]; 63 | --countReady; 64 | this->triggerRead(fd); 65 | } 66 | 67 | for (unsigned i = 0; i < writeFDs.fd_count; ++i) 68 | { 69 | int fd = writeFDs.fd_array[i]; 70 | --countReady; 71 | this->triggerWrite(fd); 72 | } 73 | #else 74 | for (int fd = 0; fd <= mMaxFd && countReady > 0; ++fd) 75 | { 76 | if (FD_ISSET(fd, &readFDs)) 77 | { 78 | --countReady; 79 | this->triggerRead(fd); 80 | } 81 | 82 | if (FD_ISSET(fd, &writeFDs)) 83 | { 84 | --countReady; 85 | this->triggerWrite(fd); 86 | } 87 | } 88 | #endif 89 | } 90 | 91 | bool SelectPoller::doRegisterForRead(int fd) 92 | { 93 | #ifndef _WIN32 94 | if ((fd < 0) || (FD_SETSIZE <= fd)) 95 | { 96 | ErrorPrint("SelectPoller::doRegisterForRead() Tried to register invalid fd(%d) FD_SETSIZE(%d)", fd, FD_SETSIZE); 97 | 98 | return false; 99 | } 100 | #else 101 | if (mFdReadSet.fd_count >= FD_SETSIZE) 102 | { 103 | ErrorPrint("SelectPoller::doRegisterForRead() Tried to register invalid fd(%d) FD_SETSIZE(%d)", fd, FD_SETSIZE); 104 | 105 | return false; 106 | } 107 | #endif 108 | 109 | if (FD_ISSET(fd, &mFdReadSet)) 110 | return false; 111 | 112 | FD_SET(fd, &mFdReadSet); 113 | mMaxFd = max(fd, mMaxFd); 114 | 115 | return true; 116 | } 117 | 118 | bool SelectPoller::doRegisterForWrite(int fd) 119 | { 120 | #ifndef _WIN32 121 | if ((fd < 0) || (FD_SETSIZE <= fd)) 122 | { 123 | ErrorPrint("SelectPoller::doRegisterForWrite() Tried to register invalid fd(%d) FD_SETSIZE(%d)", fd, FD_SETSIZE); 124 | 125 | return false; 126 | } 127 | #else 128 | if (mFdWriteSet.fd_count >= FD_SETSIZE) 129 | { 130 | ErrorLn("SelectPoller::doRegisterForWrite() Tried to register invalid fd("<recalcMaxFD(); 167 | } 168 | 169 | return true; 170 | } 171 | 172 | bool SelectPoller::doDeregisterForWrite(int fd) 173 | { 174 | #ifndef _WIN32 175 | if ((fd < 0) || (FD_SETSIZE <= fd)) 176 | { 177 | return false; 178 | } 179 | #endif 180 | 181 | if (!FD_ISSET(fd, &mFdWriteSet)) 182 | { 183 | return false; 184 | } 185 | 186 | FD_CLR(fd, &mFdWriteSet); 187 | 188 | if (fd == mMaxFd) 189 | { 190 | mMaxFd = this->recalcMaxFD(); 191 | } 192 | 193 | --mFdWriteCount; 194 | return true; 195 | } 196 | 197 | NAMESPACE_END // namespace tun 198 | -------------------------------------------------------------------------------- /src/message_receiver.h: -------------------------------------------------------------------------------- 1 | #ifndef __MESSAGERECEIVER_H__ 2 | #define __MESSAGERECEIVER_H__ 3 | 4 | #include "fasttun_base.h" 5 | 6 | NAMESPACE_BEG(msg) 7 | 8 | template 9 | class MessageReceiver 10 | { 11 | typedef void (T::*RecvFunc)(const void *, SizeType, void *); 12 | typedef void (T::*RecvErrFunc)(void *); 13 | public: 14 | MessageReceiver(T *host, RecvFunc recvFunc, RecvErrFunc recvErrFunc) 15 | :mRcvdState(MsgRcvState_NoData) 16 | ,mRcvdMsgLen(0) 17 | ,mHost(host) 18 | ,mRecvFunc(recvFunc) 19 | ,mRecvErrFunc(recvErrFunc) 20 | { 21 | assert(mHost && mRecvFunc && mRecvErrFunc); 22 | memset(&mRcvdLenBuf, 0, sizeof(mRcvdLenBuf)); 23 | memset(&mCurMsg, 0, sizeof(mCurMsg)); 24 | } 25 | 26 | virtual ~MessageReceiver() 27 | { 28 | if (mCurMsg.ptr) 29 | free(mCurMsg.ptr); 30 | } 31 | 32 | void input(const void *data, SizeType datalen, void *user) 33 | { 34 | const char *ptr = (const char *)data; 35 | for (;;) 36 | { 37 | SizeType leftlen = parseMessage(ptr, datalen); 38 | if (MsgRcvState_Error == mRcvdState) 39 | { 40 | (mHost->*mRecvErrFunc)(user); 41 | break; 42 | } 43 | else if (MsgRcvState_RcvComplete == mRcvdState) 44 | { 45 | (mHost->*mRecvFunc)(mCurMsg.ptr, mCurMsg.len, user); 46 | clearCurMsg(); 47 | } 48 | 49 | if (leftlen > 0) 50 | { 51 | ptr += (datalen-leftlen); 52 | datalen = leftlen; 53 | } 54 | else 55 | { 56 | break; 57 | } 58 | } 59 | } 60 | 61 | void clear() 62 | { 63 | clearCurMsg(); 64 | } 65 | 66 | private: 67 | SizeType parseMessage(const void *data, SizeType datalen) 68 | { 69 | const char *ptr = (const char *)data; 70 | 71 | // 先收取消息长度 72 | if (MsgRcvState_NoData == mRcvdState) 73 | { 74 | assert(sizeof(SizeType) >= mRcvdLenBuf.curlen); 75 | SizeType copylen = sizeof(SizeType)-mRcvdLenBuf.curlen; 76 | copylen = min(copylen, datalen); 77 | 78 | if (copylen > 0) 79 | { 80 | memcpy(mRcvdLenBuf.buf+mRcvdLenBuf.curlen, ptr, copylen); 81 | mRcvdLenBuf.curlen += copylen; 82 | ptr += copylen; 83 | datalen -= copylen; 84 | } 85 | if (mRcvdLenBuf.curlen == sizeof(SizeType)) // 消息长度已获取 86 | { 87 | MemoryStream stream; 88 | stream.append(mRcvdLenBuf.buf, sizeof(SizeType)); 89 | stream>>mCurMsg.len; 90 | if (mCurMsg.len > MaxLen) 91 | { 92 | mRcvdState = MsgRcvState_Error; 93 | mCurMsg.len = 0; 94 | return datalen; 95 | } 96 | 97 | mRcvdState = MsgRcvState_RcvdHead; 98 | mRcvdMsgLen = 0; 99 | mCurMsg.ptr = (char *)malloc(mCurMsg.len); 100 | assert(mCurMsg.ptr != NULL && "mCurMsg.ptr != NULL"); 101 | } 102 | } 103 | 104 | // 再收取消息内容 105 | if (MsgRcvState_RcvdHead == mRcvdState) 106 | { 107 | assert(mCurMsg.len >= mRcvdMsgLen); 108 | SizeType copylen = mCurMsg.len-mRcvdMsgLen; 109 | copylen = min(copylen, datalen); 110 | 111 | if (copylen > 0) 112 | { 113 | memcpy(mCurMsg.ptr+mRcvdMsgLen, ptr, copylen); 114 | mRcvdMsgLen += copylen; 115 | ptr += copylen; 116 | datalen -= copylen; 117 | } 118 | if (mRcvdMsgLen == mCurMsg.len) // 消息体已获取 119 | { 120 | mRcvdState = MsgRcvState_RcvComplete; 121 | } 122 | } 123 | 124 | return datalen; 125 | } 126 | 127 | void clearCurMsg() 128 | { 129 | mRcvdState = MsgRcvState_NoData; 130 | 131 | memset(&mRcvdLenBuf, 0, sizeof(mRcvdLenBuf)); 132 | 133 | if (mCurMsg.ptr) 134 | free(mCurMsg.ptr); 135 | mRcvdMsgLen = 0; 136 | memset(&mCurMsg, 0, sizeof(mCurMsg)); 137 | } 138 | 139 | private: 140 | enum EMsgRcvState 141 | { 142 | MsgRcvState_NoData, 143 | MsgRcvState_Error, 144 | MsgRcvState_RcvdHead, 145 | MsgRcvState_RcvComplete, 146 | }; 147 | 148 | struct MessageLenBuf 149 | { 150 | SizeType curlen; 151 | char buf[sizeof(SizeType)]; 152 | }; 153 | 154 | struct Message 155 | { 156 | SizeType len; 157 | char *ptr; 158 | }; 159 | 160 | // message parse state 161 | EMsgRcvState mRcvdState; 162 | 163 | // message header 164 | MessageLenBuf mRcvdLenBuf; 165 | 166 | // message body 167 | SizeType mRcvdMsgLen; 168 | Message mCurMsg; 169 | 170 | // message dealer 171 | T *mHost; 172 | RecvFunc mRecvFunc; 173 | RecvErrFunc mRecvErrFunc; 174 | }; 175 | 176 | NAMESPACE_END // namespace msg 177 | 178 | #endif // __MESSAGERECEIVER_H__ 179 | -------------------------------------------------------------------------------- /src/fast_connection.cpp: -------------------------------------------------------------------------------- 1 | #include "fast_connection.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | //-------------------------------------------------------------------------- 6 | template 7 | class ConvGen : public IDGenerator 8 | { 9 | typedef IDGenerator IDGen; 10 | public: 11 | ConvGen() : IDGen() 12 | { 13 | static const uint32 BEGID = 100; 14 | for (uint32 id = BEGID; id < BEGID+MaxNum; ++id) 15 | { 16 | this->restorId(id); 17 | } 18 | } 19 | 20 | virtual ~ConvGen() 21 | { 22 | this->mAvailableIds.clear(); 23 | } 24 | }; 25 | 26 | static ConvGen<10000> s_convGen; 27 | //-------------------------------------------------------------------------- 28 | 29 | FastConnection::~FastConnection() 30 | { 31 | shutdown(); 32 | delete mMsgRcv; 33 | delete mCache; 34 | } 35 | 36 | bool FastConnection::acceptConnection(int connfd) 37 | { 38 | shutdown(); 39 | 40 | uint32 conv = 0; 41 | if (!s_convGen.genNewId(conv)) 42 | { 43 | ErrorPrint("FastConnection::acceptConnection() no available convids!"); 44 | return false; 45 | } 46 | 47 | // create a connection object on an exists socket 48 | mpConnection = new Connection(mEventPoller); 49 | if (!mpConnection->acceptConnection(connfd)) 50 | { 51 | delete mpConnection; 52 | mpConnection = NULL; 53 | s_convGen.restorId(conv); 54 | return false; 55 | } 56 | mpConnection->setEventHandler(this); 57 | 58 | // create kcp tunnel 59 | mbTunnelConnected = false; 60 | mpKcpTunnel = mpTunnelGroup->createTunnel(conv); 61 | if (NULL == mpKcpTunnel) 62 | { 63 | s_convGen.restorId(conv); 64 | return false; 65 | } 66 | 67 | mpKcpTunnel->setEventHandler(this); 68 | MemoryStream stream; 69 | stream<setEventHandler(this); 95 | if (!mpConnection->connect(sa, salen)) 96 | { 97 | delete mpConnection; 98 | mpConnection = NULL; 99 | return false; 100 | } 101 | 102 | return true; 103 | } 104 | 105 | void FastConnection::shutdown() 106 | { 107 | mMsgRcv->clear(); 108 | if (mpKcpTunnel) 109 | { 110 | s_convGen.restorId(mpKcpTunnel->getConv()); 111 | mpTunnelGroup->destroyTunnel(mpKcpTunnel); 112 | mbTunnelConnected = false; 113 | mpKcpTunnel = NULL; 114 | } 115 | if (mpConnection) 116 | { 117 | mpConnection->shutdown(); 118 | delete mpConnection; 119 | mpConnection = NULL; 120 | } 121 | } 122 | 123 | int FastConnection::send(const void *data, size_t datalen) 124 | { 125 | if (mpKcpTunnel && mbTunnelConnected) 126 | { 127 | _flushAll(); 128 | return mpKcpTunnel->send(data, datalen); 129 | } 130 | 131 | mCache->cache(data, datalen); 132 | return datalen; 133 | } 134 | 135 | void FastConnection::_flushAll() 136 | { 137 | if (mpKcpTunnel && mbTunnelConnected && !mCache->empty()) 138 | { 139 | mCache->flushAll(); 140 | } 141 | } 142 | 143 | bool FastConnection::flush(const void *data, size_t datalen) 144 | { 145 | mpKcpTunnel->send(data, datalen); 146 | return true; 147 | } 148 | 149 | void FastConnection::triggerHeartBeatPacket() 150 | { 151 | mHeartBeatRecord.packetSentTime = core::getClock(); 152 | sendMessage(MsgId_HeartBeat_Request, NULL, 0); 153 | } 154 | 155 | const HeartBeatRecord& FastConnection::getHeartBeatRecord() const 156 | { 157 | return mHeartBeatRecord; 158 | } 159 | 160 | void FastConnection::onConnected(Connection *pConn) 161 | { 162 | if (mpHandler) 163 | mpHandler->onConnected(this); 164 | } 165 | 166 | void FastConnection::onDisconnected(Connection *pConn) 167 | { 168 | shutdown(); 169 | if (mpHandler) 170 | mpHandler->onDisconnected(this); 171 | } 172 | 173 | void FastConnection::onRecv(Connection *pConn, const void *data, size_t datalen) 174 | { 175 | mMsgRcv->input(data, datalen, pConn); 176 | } 177 | 178 | void FastConnection::onError(Connection *pConn) 179 | { 180 | shutdown(); 181 | if (mpHandler) 182 | mpHandler->onError(this); 183 | } 184 | 185 | void FastConnection::onRecv(const void *data, size_t datalen) 186 | { 187 | if (mpHandler) 188 | mpHandler->onRecv(this, data, datalen); 189 | } 190 | 191 | void FastConnection::onRecvMsg(const void *data, uint8 datalen, void *user) 192 | { 193 | MemoryStream stream; 194 | stream.append((const uint8 *)data, (size_t)datalen); 195 | assert(stream.length() >= sizeof(int) && "handleMessage() stream.length() > sizeof(int)"); 196 | 197 | bool notifyKcpTunnelCreateFailed = false; 198 | int msgid = 0; 199 | stream>>msgid; 200 | switch (msgid) 201 | { 202 | case MsgId_CreateKcpTunnel: 203 | { 204 | uint32 conv = 0; 205 | stream>>conv; 206 | assert(NULL == mpKcpTunnel && "FastConnection::handleMessage() NULL == mpKcpTunnel"); 207 | mpKcpTunnel = mpTunnelGroup->createTunnel(conv); 208 | if (NULL == mpKcpTunnel) 209 | { 210 | ErrorPrint("FastConnection::handleMessage() fail to create kcp tunnel!"); 211 | notifyKcpTunnelCreateFailed = true; 212 | break; 213 | } 214 | 215 | mpKcpTunnel->setEventHandler(this); 216 | mbTunnelConnected = true; 217 | sendMessage(MsgId_ConfirmCreateKcpTunnel, NULL, 0); 218 | _flushAll(); 219 | } 220 | break; 221 | case MsgId_ConfirmCreateKcpTunnel: 222 | { 223 | if (NULL == mpKcpTunnel) 224 | { 225 | ErrorPrint("FastConnection::handleMessage() we have no kcptunnel on server!"); 226 | notifyKcpTunnelCreateFailed = true; 227 | break; 228 | } 229 | mbTunnelConnected = true; 230 | _flushAll(); 231 | } 232 | break; 233 | case MsgId_HeartBeat_Request: 234 | sendMessage(MsgId_HeartBeat_Response, NULL, 0); 235 | break; 236 | case MsgId_HeartBeat_Response: 237 | mHeartBeatRecord.packetRecvTime = core::getClock(); 238 | break; 239 | default: 240 | ErrorPrint("FastConnection::handleMessage() undefined message!"); 241 | break; 242 | } 243 | 244 | if (notifyKcpTunnelCreateFailed && mpHandler) 245 | mpHandler->onCreateKcpTunnelFailed(this); 246 | } 247 | 248 | void FastConnection::onRecvMsgErr(void *user) 249 | { 250 | onError((Connection *)user); 251 | } 252 | 253 | void FastConnection::sendMessage(int msgid, const void *data, size_t datalen) 254 | { 255 | if (NULL == mpConnection) 256 | { 257 | ErrorPrint("FastConnection::sendMessage() NULL == mpConnection"); 258 | return; 259 | } 260 | if (!mpConnection->isConnected()) 261 | { 262 | ErrorPrint("FastConnection::sendMessage() mpConnection is not connected"); 263 | return; 264 | } 265 | 266 | MemoryStream stream; 267 | uint8 msglen = sizeof(msgid)+datalen; 268 | stream< 0) 271 | stream.append((const uint8 *)data, (size_t)datalen); 272 | mpConnection->send(stream.data(), stream.length()); 273 | } 274 | 275 | NAMESPACE_END // namespace tun 276 | -------------------------------------------------------------------------------- /src/test.cpp: -------------------------------------------------------------------------------- 1 | #include "fasttun_base.h" 2 | #include "select_poller.h" 3 | #include "epoll_poller.h" 4 | #include "listener.h" 5 | #include "connection.h" 6 | #include "kcp_tunnel.h" 7 | #include "fast_connection.h" 8 | #include "cache.h" 9 | 10 | using namespace tun; 11 | 12 | static sockaddr_in ListenAddr; 13 | static sockaddr_in RemoteAddr; 14 | 15 | //-------------------------------------------------------------------------- 16 | class ClientBridge : public Connection::Handler 17 | { 18 | public: 19 | struct Handler 20 | { 21 | virtual void onIntConnDisconnected(ClientBridge *pBridge) = 0; 22 | virtual void onIntConnError(ClientBridge *pBridge) = 0; 23 | }; 24 | 25 | ClientBridge(EventPoller *poller, Handler *l) 26 | :mEventPoller(poller) 27 | ,mpHandler(l) 28 | ,mpIntConn(NULL) 29 | ,mpExtConn(NULL) 30 | ,mCache(NULL) 31 | ,mLastExtConnTime(0) 32 | { 33 | mCache = new MyCache(this, &ClientBridge::flush); 34 | } 35 | 36 | virtual ~ClientBridge() 37 | { 38 | shutdown(); 39 | delete mCache; 40 | } 41 | 42 | bool acceptConnection(int connfd) 43 | { 44 | assert(NULL == mpIntConn && NULL == mpExtConn && 45 | "NULL == mpIntConn && NULL == mpExtConn"); 46 | 47 | mpIntConn = new Connection(mEventPoller); 48 | if (!mpIntConn->acceptConnection(connfd)) 49 | { 50 | delete mpIntConn; 51 | mpIntConn = NULL; 52 | return false; 53 | } 54 | mpIntConn->setEventHandler(this); 55 | 56 | mpExtConn = new Connection(mEventPoller); 57 | mLastExtConnTime = core::getClock(); 58 | if (!mpExtConn->connect((const SA *)&RemoteAddr, sizeof(RemoteAddr))) 59 | { 60 | mpIntConn->shutdown(); 61 | delete mpIntConn; 62 | mpIntConn = NULL; 63 | delete mpExtConn; 64 | mpExtConn = NULL; 65 | return false; 66 | } 67 | mpExtConn->setEventHandler(this); 68 | 69 | return true; 70 | } 71 | 72 | void shutdown() 73 | { 74 | if (mpIntConn) 75 | { 76 | mpIntConn->shutdown(); 77 | delete mpIntConn; 78 | mpIntConn = NULL; 79 | } 80 | if (mpExtConn) 81 | { 82 | mpExtConn->shutdown(); 83 | delete mpExtConn; 84 | mpExtConn = NULL; 85 | } 86 | } 87 | 88 | Connection* getIntConn() const 89 | { 90 | return mpIntConn; 91 | } 92 | 93 | // Connection::Handler 94 | virtual void onConnected(Connection *pConn) 95 | { 96 | if (pConn == mpExtConn) 97 | { 98 | DebugPrint("ss connected!"); 99 | _flushAll(); 100 | } 101 | } 102 | 103 | virtual void onDisconnected(Connection *pConn) 104 | { 105 | if (pConn == mpIntConn) 106 | { 107 | if (mpHandler) 108 | mpHandler->onIntConnDisconnected(this); 109 | } 110 | } 111 | 112 | virtual void onRecv(Connection *pConn, const void *data, size_t datalen) 113 | { 114 | if (pConn == mpIntConn) 115 | { 116 | if (!mpExtConn->isConnected()) 117 | { 118 | _reconnectExternal(); 119 | mCache->cache(data, datalen); 120 | } 121 | else 122 | { 123 | _flushAll(); 124 | mpExtConn->send(data, datalen); 125 | } 126 | DebugPrint("internal recvlen=%u", datalen); 127 | } 128 | else 129 | { 130 | mpIntConn->send(data, datalen); 131 | DebugPrint("external recvlen=%u", datalen); 132 | } 133 | } 134 | 135 | virtual void onError(Connection *pConn) 136 | { 137 | if (pConn == mpIntConn) 138 | { 139 | if (mpHandler) 140 | mpHandler->onIntConnError(this); 141 | } 142 | } 143 | 144 | void _reconnectExternal() 145 | { 146 | ulong curtick = core::getClock(); 147 | if (curtick > mLastExtConnTime+1000) 148 | { 149 | mLastExtConnTime = curtick; 150 | mpExtConn->connect((const SA *)&RemoteAddr, sizeof(RemoteAddr)); 151 | } 152 | } 153 | 154 | void _flushAll() 155 | { 156 | if (mpExtConn->isConnected()) 157 | { 158 | mCache->flushAll(); 159 | } 160 | } 161 | bool flush(const void *data, size_t datalen) 162 | { 163 | mpExtConn->send(data, datalen); 164 | return true; 165 | } 166 | 167 | private: 168 | typedef Cache MyCache; 169 | 170 | EventPoller *mEventPoller; 171 | Handler *mpHandler; 172 | 173 | Connection *mpIntConn; 174 | Connection *mpExtConn; 175 | 176 | MyCache *mCache; 177 | 178 | ulong mLastExtConnTime; 179 | }; 180 | //-------------------------------------------------------------------------- 181 | 182 | //-------------------------------------------------------------------------- 183 | class Client : public Listener::Handler, public ClientBridge::Handler 184 | { 185 | public: 186 | Client(EventPoller *poller) 187 | :Listener::Handler() 188 | ,mEventPoller(poller) 189 | ,mListener(poller) 190 | ,mBridges() 191 | { 192 | } 193 | 194 | virtual ~Client() 195 | { 196 | } 197 | 198 | bool create() 199 | { 200 | if (!mListener.initialise((const SA *)&ListenAddr, sizeof(ListenAddr))) 201 | { 202 | ErrorPrint("create listener failed."); 203 | return false; 204 | } 205 | mListener.setEventHandler(this); 206 | 207 | return true; 208 | } 209 | 210 | void finalise() 211 | { 212 | mListener.finalise(); 213 | BridgeList::iterator it = mBridges.begin(); 214 | for (; it != mBridges.end(); ++it) 215 | { 216 | ClientBridge *bridge = *it; 217 | if (bridge) 218 | { 219 | bridge->shutdown(); 220 | delete bridge; 221 | } 222 | } 223 | mBridges.clear(); 224 | } 225 | 226 | virtual void onAccept(int connfd) 227 | { 228 | ClientBridge *bridge = new ClientBridge(mEventPoller, this); 229 | if (!bridge->acceptConnection(connfd)) 230 | { 231 | delete bridge; 232 | return; 233 | } 234 | 235 | mBridges.insert(bridge); 236 | DebugPrint("a connection createted! cursize:%u", mBridges.size()); 237 | } 238 | 239 | virtual void onIntConnDisconnected(ClientBridge *pBridge) 240 | { 241 | onBridgeShut(pBridge); 242 | DebugPrint("a connection closed! cursize:%u", mBridges.size()); 243 | } 244 | 245 | virtual void onIntConnError(ClientBridge *pBridge) 246 | { 247 | onBridgeShut(pBridge); 248 | DebugPrint("a connection occur error! cursize:%u reason:%s", mBridges.size(), coreStrError()); 249 | } 250 | 251 | private: 252 | void onBridgeShut(ClientBridge *pBridge) 253 | { 254 | BridgeList::iterator it = mBridges.find(pBridge); 255 | if (it != mBridges.end()) 256 | { 257 | mBridges.erase(it); 258 | } 259 | 260 | pBridge->shutdown(); 261 | delete pBridge; 262 | } 263 | 264 | private: 265 | typedef std::set BridgeList; 266 | 267 | EventPoller *mEventPoller; 268 | Listener mListener; 269 | 270 | BridgeList mBridges; 271 | }; 272 | //-------------------------------------------------------------------------- 273 | 274 | int main(int argc, char *argv[]) 275 | { 276 | // initialise log 277 | if (log_initialise(AllLog) != 0) 278 | { 279 | fprintf(stderr, "init log failed!"); 280 | exit(1); 281 | } 282 | log_reg_console(); 283 | 284 | // parse parameter 285 | const char *confPath = NULL; 286 | const char *listenAddr = NULL; 287 | const char *remoteAddr = NULL; 288 | 289 | int opt = 0; 290 | while ((opt = getopt(argc, argv, "c:l:r:")) != -1) 291 | { 292 | switch (opt) 293 | { 294 | case 'c': 295 | confPath = optarg; 296 | break; 297 | case 'l': 298 | listenAddr = optarg; 299 | break; 300 | case 'r': 301 | remoteAddr = optarg; 302 | break; 303 | default: 304 | break; 305 | } 306 | } 307 | 308 | if (argc == 1) 309 | { 310 | confPath = DEFAULT_CONF_PATH; 311 | } 312 | if (confPath) 313 | { 314 | Ini ini(confPath); 315 | static std::string s_listenAddr = ini.getString("test", "listen", ""); 316 | static std::string s_remoteAddr = ini.getString("test", "remote", ""); 317 | if (s_listenAddr != "") 318 | listenAddr = s_listenAddr.c_str(); 319 | if (s_remoteAddr != "") 320 | remoteAddr = s_remoteAddr.c_str(); 321 | } 322 | 323 | if (NULL == listenAddr || NULL == remoteAddr) 324 | { 325 | fprintf(stderr, "no argument assigned or parse argument failed!\n"); 326 | log_finalise(); 327 | exit(EXIT_FAILURE); 328 | } 329 | if (!core::str2Ipv4(listenAddr, ListenAddr) || !core::str2Ipv4(remoteAddr, RemoteAddr)) 330 | { 331 | ErrorPrint("invalid socket address!"); 332 | log_finalise(); 333 | exit(EXIT_FAILURE); 334 | } 335 | 336 | // create event poller 337 | #ifdef HAS_EPOLL 338 | EventPoller *netPoller = new EpollPoller(); 339 | #else 340 | EventPoller *netPoller = new SelectPoller(); 341 | #endif 342 | 343 | // create client 344 | Client cli(netPoller); 345 | if (!cli.create()) 346 | { 347 | ErrorPrint("create client error!"); 348 | delete netPoller; 349 | log_finalise(); 350 | exit(EXIT_FAILURE); 351 | } 352 | 353 | for (;;) 354 | { 355 | netPoller->processPendingEvents(-1); 356 | } 357 | 358 | cli.finalise(); 359 | delete netPoller; 360 | 361 | // uninit log 362 | log_finalise(); 363 | exit(0); 364 | } 365 | -------------------------------------------------------------------------------- /src/kcp_tunnel.inl: -------------------------------------------------------------------------------- 1 | NAMESPACE_BEG(tun) 2 | 3 | //-------------------------------------------------------------------------- 4 | static int kcpOutput(const char *buf, int len, ikcpcb *kcp, void *user) 5 | { 6 | ITunnel *pTunnel = (ITunnel *)user; 7 | if (pTunnel) 8 | { 9 | pTunnel->_output(buf, len); 10 | } 11 | return 0; 12 | } 13 | 14 | template 15 | KcpTunnel::~KcpTunnel() 16 | { 17 | shutdown(); 18 | delete mSndCache; 19 | } 20 | 21 | template 22 | bool KcpTunnel::create(uint32 conv, const KcpArg &arg) 23 | { 24 | if (mKcpCb) 25 | shutdown(); 26 | 27 | mConv = conv; 28 | mKcpCb = ikcp_create(mConv, this); 29 | if (NULL == mKcpCb) 30 | return false; 31 | 32 | mKcpCb->output = kcpOutput; 33 | ikcp_nodelay(mKcpCb, arg.nodelay, arg.interval, arg.resend, arg.nc); 34 | ikcp_setmtu(mKcpCb, arg.mtu); 35 | mSentCount = mRecvCount = 0; 36 | DebugPrint("create kcp! conv=%u", conv); 37 | return true; 38 | } 39 | 40 | template 41 | void KcpTunnel::shutdown() 42 | { 43 | if (mKcpCb) 44 | { 45 | if (mKcpCb->nrcv_que || mKcpCb->nsnd_que) 46 | { 47 | WarningPrint("close kcp! conv=%u" 48 | " sentcount=%d recvcount=%d" 49 | " snd_nxt=%u rcv_nxt=%u" 50 | " peeksize=%d" 51 | " nrcv_que=%u nsnd_que=%u" 52 | " snd_wnd=%u rmt_wnd=%u" 53 | " snd_una=%u cwnd=%u", 54 | mConv, 55 | mSentCount, mRecvCount, 56 | mKcpCb->snd_nxt, mKcpCb->rcv_nxt, 57 | ikcp_peeksize(mKcpCb), 58 | mKcpCb->nrcv_que, mKcpCb->nsnd_que, 59 | mKcpCb->snd_wnd, mKcpCb->rmt_wnd, 60 | mKcpCb->snd_una, mKcpCb->cwnd); 61 | } 62 | else 63 | { 64 | DebugPrint("close kcp! conv=%u" 65 | " sentcount=%d recvcount=%d" 66 | " snd_nxt=%u rcv_nxt=%u" 67 | " peeksize=%d" 68 | " nrcv_que=%u nsnd_que=%u" 69 | " snd_wnd=%u rmt_wnd=%u" 70 | " snd_una=%u cwnd=%u", 71 | mConv, 72 | mSentCount, mRecvCount, 73 | mKcpCb->snd_nxt, mKcpCb->rcv_nxt, 74 | ikcp_peeksize(mKcpCb), 75 | mKcpCb->nrcv_que, mKcpCb->nsnd_que, 76 | mKcpCb->snd_wnd, mKcpCb->rmt_wnd, 77 | mKcpCb->snd_una, mKcpCb->cwnd); 78 | } 79 | 80 | ikcp_release(mKcpCb); 81 | mKcpCb = NULL; 82 | } 83 | mSentCount = mRecvCount = 0; 84 | } 85 | 86 | template 87 | int KcpTunnel::send(const void *data, size_t datalen) 88 | { 89 | if (this->_canFlush() && 90 | this->_flushAll() && 91 | this->flushSndBuf(data, datalen)) 92 | { 93 | return 0; 94 | } 95 | 96 | mSndCache->cache(data, datalen); 97 | return 0; 98 | } 99 | 100 | template 101 | bool KcpTunnel::_flushAll() 102 | { 103 | if (this->_canFlush()) 104 | { 105 | return mSndCache->flushAll(); 106 | } 107 | return false; 108 | } 109 | 110 | template 111 | bool KcpTunnel::flushSndBuf(const void *data, size_t datalen) 112 | { 113 | if (!this->_canFlush()) 114 | return false; 115 | 116 | const char *ptr = (const char *)data; 117 | size_t maxLen = mKcpCb->mss<<4; 118 | for (;;) 119 | { 120 | if (datalen <= maxLen) // in most case 121 | { 122 | ikcp_send(mKcpCb, (const char *)ptr, datalen); 123 | ++mSentCount; 124 | break; 125 | } 126 | else 127 | { 128 | ikcp_send(mKcpCb, (const char *)ptr, maxLen); 129 | ++mSentCount; 130 | ptr += maxLen; 131 | datalen -= maxLen; 132 | } 133 | } 134 | return true; 135 | } 136 | 137 | template 138 | bool KcpTunnel::_canFlush() const 139 | { 140 | return ikcp_waitsnd(mKcpCb) < 2*(int)mKcpCb->snd_wnd; 141 | } 142 | 143 | template 144 | bool KcpTunnel::input(const void *data, size_t datalen) 145 | { 146 | int ret = ikcp_input(mKcpCb, (const char *)data, datalen); 147 | return 0 == ret; 148 | } 149 | 150 | template 151 | uint32 KcpTunnel::update(uint32 current) 152 | { 153 | ikcp_update(mKcpCb, current); 154 | _flushAll(); 155 | 156 | int datalen = ikcp_peeksize(mKcpCb); 157 | if (datalen > 0) 158 | { 159 | char *buf = (char *)malloc(datalen); 160 | assert(buf != NULL && "ikcp_recv() malloc failed!"); 161 | assert(ikcp_recv(mKcpCb, buf, datalen) == datalen); 162 | 163 | ++mRecvCount; 164 | if (mHandler) 165 | mHandler->onRecv(buf, datalen); 166 | free(buf); 167 | } 168 | 169 | uint32 nextCallTime = ikcp_check(mKcpCb, current); 170 | return nextCallTime > current ? nextCallTime - current : 0; 171 | } 172 | //-------------------------------------------------------------------------- 173 | 174 | //-------------------------------------------------------------------------- 175 | template 176 | KcpTunnelGroup::~KcpTunnelGroup() 177 | { 178 | } 179 | 180 | template 181 | bool KcpTunnelGroup::create(const char *addr) 182 | { 183 | if (!Supper::create(addr)) 184 | { 185 | return false; 186 | } 187 | 188 | return this->_create(); 189 | } 190 | 191 | template 192 | bool KcpTunnelGroup::create(const SA* sa, socklen_t salen) 193 | { 194 | if (!Supper::create(sa, salen)) 195 | { 196 | return false; 197 | } 198 | 199 | return this->_create(); 200 | } 201 | 202 | template 203 | bool KcpTunnelGroup::_create() 204 | { 205 | // register for event 206 | if (!mEventPoller->registerForRead(this->mFd, this)) 207 | { 208 | ErrorPrint("KcpTunnelGroup::create() register error!"); 209 | return false; 210 | } 211 | return true; 212 | } 213 | 214 | template 215 | void KcpTunnelGroup::shutdown() 216 | { 217 | tryUnregWriteEvent(); 218 | mOutputNotifyList.clear(); 219 | 220 | typename Tunnels::iterator it = this->mTunnels.begin(); 221 | for (; it != this->mTunnels.end(); ++it) 222 | { 223 | Tun *pTunnel = it->second; 224 | if (pTunnel) 225 | { 226 | pTunnel->shutdown(); 227 | delete pTunnel; 228 | } 229 | } 230 | this->mTunnels.clear(); 231 | 232 | if (this->mFd >= 0) 233 | { 234 | mEventPoller->deregisterForRead(this->mFd); 235 | close(this->mFd); 236 | this->mFd = -1; 237 | } 238 | } 239 | 240 | template 241 | ITunnel* KcpTunnelGroup::createTunnel(uint32 conv) 242 | { 243 | typename Tunnels::iterator it = this->mTunnels.find(conv); 244 | if (it != this->mTunnels.end()) 245 | { 246 | ErrorPrint("KcpTunnelGroup::createTunnel() tunnul already exist! conv=%u", conv); 247 | return NULL; 248 | } 249 | 250 | Tun *pTunnel = new Tun(this); 251 | if (!pTunnel->create(conv, mKcpArg)) 252 | { 253 | return NULL; 254 | } 255 | 256 | this->mTunnels.insert(std::pair(conv, pTunnel)); 257 | return pTunnel; 258 | } 259 | 260 | template 261 | void KcpTunnelGroup::destroyTunnel(ITunnel *pTunnel) 262 | { 263 | uint32 conv = pTunnel->getConv(); 264 | 265 | typename Tunnels::iterator it = this->mTunnels.find(conv); 266 | if (it != this->mTunnels.end()) 267 | { 268 | this->mTunnels.erase(it); 269 | } 270 | 271 | static_cast(pTunnel)->shutdown(); 272 | delete pTunnel; 273 | } 274 | 275 | template 276 | void KcpTunnelGroup::regOutputNotification(OutputNotificationHandler *p) 277 | { 278 | mOutputNotifyList.insert(p); 279 | tryRegWriteEvent(); 280 | } 281 | 282 | template 283 | void KcpTunnelGroup::unregOutputNotification(OutputNotificationHandler *p) 284 | { 285 | OutputNotifyList::iterator it = mOutputNotifyList.find(p); 286 | if (it != mOutputNotifyList.end()) 287 | { 288 | mOutputNotifyList.erase(it); 289 | if (mOutputNotifyList.empty()) 290 | { 291 | tryUnregWriteEvent(); 292 | } 293 | } 294 | } 295 | 296 | template 297 | uint32 KcpTunnelGroup::update() 298 | { 299 | // update all tunnels 300 | uint32 current = core::getClock(); 301 | uint32 maxWait = 0xFFFFFFFF; 302 | typename Tunnels::iterator it = this->mTunnels.begin(); 303 | for (; it != this->mTunnels.end(); ++it) 304 | { 305 | Tun *pTunnel = it->second; 306 | if (pTunnel) 307 | { 308 | maxWait = min(maxWait, pTunnel->update(current)); 309 | } 310 | } 311 | return maxWait; 312 | } 313 | 314 | template 315 | int KcpTunnelGroup::handleInputNotification(int fd) 316 | { 317 | // recv data from internet 318 | int maxlen = mKcpArg.mtu; 319 | char *buf = (char *)malloc(maxlen); 320 | assert(buf != NULL && "udp recv! malloc failed!"); 321 | 322 | sockaddr_in addr; 323 | socklen_t addrlen = sizeof(addr); 324 | int recvlen = recvfrom(fd, buf, maxlen, 0, (SA *)&addr, &addrlen); 325 | 326 | // input to kcp 327 | if (recvlen > 0) 328 | { 329 | uint32 conv = 0; 330 | int ret = ikcp_get_conv(buf, recvlen, (IUINT32 *)&conv); 331 | typename Tunnels::iterator it = ret ? mTunnels.find(conv) : mTunnels.end(); 332 | 333 | if (it != mTunnels.end()) 334 | { 335 | Tun *pTunnel = it->second; 336 | if (pTunnel) 337 | { 338 | pTunnel->input(buf, recvlen); 339 | pTunnel->onRecvPeerAddr((const SA *)&addr, addrlen); 340 | pTunnel->update(core::getClock()); 341 | } 342 | } 343 | } 344 | free(buf); 345 | return 0; 346 | } 347 | 348 | template 349 | int KcpTunnelGroup::handleOutputNotification(int fd) 350 | { 351 | OutputNotifyList::iterator it = mOutputNotifyList.begin(); 352 | for (; it != mOutputNotifyList.end(); ++it) 353 | { 354 | (*it)->handleOutputNotification(fd); 355 | } 356 | return 0; 357 | } 358 | //-------------------------------------------------------------------------- 359 | 360 | NAMESPACE_END // namespace tun 361 | -------------------------------------------------------------------------------- /src/connection.cpp: -------------------------------------------------------------------------------- 1 | #include "connection.h" 2 | 3 | NAMESPACE_BEG(tun) 4 | 5 | Connection::~Connection() 6 | { 7 | shutdown(); 8 | free(mBuffer); 9 | } 10 | 11 | bool Connection::acceptConnection(int connfd) 12 | { 13 | if (mFd >= 0) 14 | { 15 | ErrorPrint("[acceptConnection] accept connetion error! the conn is in use!"); 16 | return false; 17 | } 18 | 19 | mFd = connfd; 20 | 21 | // set nonblocking 22 | if (!core::setNonblocking(mFd)) 23 | { 24 | ErrorPrint("[acceptConnection] set nonblocking error! %s", coreStrError()); 25 | goto err_1; 26 | } 27 | 28 | tryRegReadEvent(); 29 | 30 | mConnStatus = ConnStatus_Connected; 31 | return true; 32 | 33 | err_1: 34 | close(mFd); 35 | mFd = -1; 36 | 37 | return false; 38 | } 39 | 40 | bool Connection::connect(const char *ip, int port) 41 | { 42 | struct sockaddr_in remoteAddr; 43 | remoteAddr.sin_family = AF_INET; 44 | remoteAddr.sin_port = htons(port); 45 | if (inet_pton(AF_INET, ip, &remoteAddr.sin_addr) < 0) 46 | { 47 | ErrorPrint("[connect] illegal ip(%s)", ip); 48 | return false; 49 | } 50 | 51 | return connect((const SA *)&remoteAddr, sizeof(remoteAddr)); 52 | } 53 | 54 | bool Connection::connect(const SA *sa, socklen_t salen) 55 | { 56 | if (mFd >= 0) 57 | shutdown(); 58 | 59 | if (mFd >= 0) 60 | { 61 | ErrorPrint("[connect] accept connetion error! the conn is in use!"); 62 | return false; 63 | } 64 | 65 | mFd = socket(AF_INET, SOCK_STREAM, 0); 66 | if (mFd < 0) 67 | { 68 | ErrorPrint("[connect] create socket error! %s", coreStrError()); 69 | return false; 70 | } 71 | 72 | // set nonblocking 73 | if (!core::setNonblocking(mFd)) 74 | { 75 | ErrorPrint("[connect] set nonblocking error! %s", coreStrError()); 76 | goto err_1; 77 | } 78 | 79 | if (::connect(mFd, sa, salen) == 0) // 连接成功 80 | { 81 | tryRegReadEvent(); 82 | mConnStatus = ConnStatus_Connected; 83 | if (mHandler) 84 | mHandler->onConnected(this); 85 | } 86 | else 87 | { 88 | if (errno == EINPROGRESS) 89 | { 90 | mConnStatus = ConnStatus_Connecting; 91 | tryRegWriteEvent(); 92 | } 93 | else 94 | { 95 | goto err_1; 96 | } 97 | } 98 | 99 | return true; 100 | 101 | err_1: 102 | close(mFd); 103 | mFd = -1; 104 | 105 | return false; 106 | } 107 | 108 | void Connection::shutdown() 109 | { 110 | if (mFd < 0) 111 | return; 112 | 113 | tryUnregWriteEvent(); 114 | tryUnregReadEvent(); 115 | close(mFd); 116 | mFd = -1; 117 | mConnStatus = ConnStatus_Closed; 118 | 119 | TcpPacketList::iterator it = mTcpPacketList.begin(); 120 | for (; it != mTcpPacketList.end(); ++it) 121 | delete *it; 122 | mTcpPacketList.clear(); 123 | } 124 | 125 | void Connection::send(const void *data, size_t datalen) 126 | { 127 | if (mFd < 0) 128 | { 129 | ErrorPrint("[send] send error! socket uninited or shuted!"); 130 | return; 131 | } 132 | if (mConnStatus != ConnStatus_Connected) 133 | { 134 | ErrorPrint("[send] can't send data in such status(%d)", mConnStatus); 135 | return; 136 | } 137 | 138 | const char *ptr = (const char *)data; 139 | if (tryFlushRemainPacket()) 140 | { 141 | int sentlen = ::send(mFd, data, datalen, 0); 142 | // int sentlen = -1; errno = EAGAIN; 143 | if ((size_t)sentlen == datalen) 144 | return; 145 | 146 | if (sentlen > 0) 147 | { 148 | ptr += sentlen; 149 | datalen -= sentlen; 150 | } 151 | } 152 | 153 | if (checkSocketErrors()) 154 | return; 155 | 156 | cachePacket(ptr, datalen); 157 | tryRegWriteEvent(); // 注册发送缓冲区可写事件 158 | } 159 | 160 | bool Connection::getpeername(SA *sa, socklen_t *salen) const 161 | { 162 | if (mFd < 0) 163 | return false; 164 | 165 | return ::getpeername(mFd, sa, salen) == 0; 166 | } 167 | 168 | bool Connection::gethostname(SA *sa, socklen_t *salen) const 169 | { 170 | if (mFd < 0) 171 | return false; 172 | 173 | return ::getsockname(mFd, sa, salen) == 0; 174 | } 175 | 176 | int Connection::handleInputNotification(int fd) 177 | { 178 | if (mConnStatus != ConnStatus_Connected) 179 | { 180 | ErrorPrint("[handleInputNotification] Connection is not connected! fd=%d", fd); 181 | return 0; 182 | } 183 | 184 | char *buf = mBuffer; 185 | int curlen = 0; 186 | for (;;) 187 | { 188 | int recvlen = recv(mFd, buf+curlen, MAXLEN, 0); 189 | if (recvlen > 0) 190 | curlen += recvlen; 191 | 192 | if (recvlen >= MAXLEN) 193 | { 194 | if (curlen >= LIMIT_LEN) 195 | break; 196 | 197 | if (buf == mBuffer) 198 | { 199 | buf = (char *)malloc(curlen+MAXLEN); 200 | memcpy(buf, mBuffer, curlen); 201 | } 202 | else 203 | { 204 | buf = (char *)realloc(buf, curlen+MAXLEN); 205 | } 206 | } 207 | else 208 | { 209 | if (recvlen < 0) 210 | { 211 | if (errno != EAGAIN && errno != EWOULDBLOCK) 212 | mConnStatus = ConnStatus_Error; 213 | } 214 | else if (recvlen == 0) 215 | { 216 | mConnStatus = ConnStatus_Closed; 217 | } 218 | break; 219 | } 220 | } 221 | 222 | if (curlen >= LIMIT_LEN) 223 | { 224 | WarningPrint("get big data! recvlen=%d", curlen); 225 | } 226 | 227 | if (curlen > 0 && mHandler) 228 | mHandler->onRecv(this, buf, curlen); 229 | if (buf != mBuffer) 230 | free(buf); 231 | 232 | if (mHandler) 233 | { 234 | if (ConnStatus_Error == mConnStatus) 235 | { 236 | tryUnregReadEvent(); 237 | tryUnregWriteEvent(); 238 | mHandler->onError(this); 239 | } 240 | else if (ConnStatus_Closed == mConnStatus) 241 | { 242 | tryUnregReadEvent(); 243 | tryUnregWriteEvent(); 244 | mHandler->onDisconnected(this); 245 | } 246 | } 247 | 248 | return 0; 249 | } 250 | 251 | int Connection::handleOutputNotification(int fd) 252 | { 253 | if (ConnStatus_Connecting == mConnStatus) 254 | { 255 | tryUnregWriteEvent(); 256 | 257 | int err = 0; 258 | socklen_t errlen = sizeof(int); 259 | if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0 || err != 0) 260 | { 261 | if (err != 0) 262 | errno = err; 263 | 264 | mConnStatus = ConnStatus_Error; 265 | if (mHandler) 266 | { 267 | tryUnregReadEvent(); 268 | tryUnregWriteEvent(); 269 | mHandler->onError(this); 270 | } 271 | 272 | return 0; 273 | } 274 | 275 | tryRegReadEvent(); 276 | mConnStatus = ConnStatus_Connected; 277 | if (mHandler) 278 | mHandler->onConnected(this); 279 | } 280 | else if (ConnStatus_Connected == mConnStatus) 281 | { 282 | tryFlushRemainPacket(); 283 | if (checkSocketErrors()) 284 | return 0; 285 | } 286 | 287 | return 0; 288 | } 289 | 290 | void Connection::tryRegReadEvent() 291 | { 292 | if (!mbRegForRead) 293 | { 294 | mbRegForRead = true; 295 | mEventPoller->registerForRead(mFd, this); 296 | } 297 | } 298 | 299 | void Connection::tryUnregReadEvent() 300 | { 301 | if (mbRegForRead) 302 | { 303 | mbRegForRead = false; 304 | mEventPoller->deregisterForRead(mFd); 305 | } 306 | } 307 | 308 | void Connection::tryRegWriteEvent() 309 | { 310 | if (!mbRegForWrite) 311 | { 312 | mbRegForWrite = true; 313 | mEventPoller->registerForWrite(mFd, this); 314 | } 315 | } 316 | 317 | void Connection::tryUnregWriteEvent() 318 | { 319 | if (mbRegForWrite) 320 | { 321 | mbRegForWrite = false; 322 | mEventPoller->deregisterForWrite(mFd); 323 | } 324 | } 325 | 326 | bool Connection::tryFlushRemainPacket() 327 | { 328 | if (mTcpPacketList.empty()) 329 | { 330 | return true; 331 | } 332 | 333 | TcpPacketList::iterator it = mTcpPacketList.begin(); 334 | for (; it != mTcpPacketList.end();) 335 | { 336 | TcpPacket *p = *it; 337 | assert(p->buflen > p->sentlen && "p->buflen > p->sentlen"); 338 | size_t len = p->buflen - p->sentlen; 339 | int sentlen = ::send(mFd, p->buf+p->sentlen, len, 0); 340 | 341 | if (len == (size_t)sentlen) 342 | { 343 | delete p; 344 | mTcpPacketList.erase(it++); 345 | continue; 346 | } 347 | 348 | if (sentlen > 0) 349 | p->sentlen += sentlen; 350 | break; 351 | } 352 | 353 | if (mTcpPacketList.empty()) 354 | { 355 | tryUnregWriteEvent(); 356 | return true; 357 | } 358 | 359 | return false; 360 | } 361 | 362 | void Connection::cachePacket(const void *data, size_t datalen) 363 | { 364 | TcpPacket *p = new TcpPacket(); assert(p && "tcppacket != NULL"); 365 | p->buf = (char *)malloc(datalen); assert(p->buf && "packet->buf != NULL"); 366 | memcpy(p->buf, data, datalen); 367 | p->buflen = datalen; 368 | p->sentlen = 0; 369 | mTcpPacketList.push_back(p); 370 | } 371 | 372 | bool Connection::checkSocketErrors() 373 | { 374 | EReason err = _checkSocketErrors(); 375 | if (err != Reason_ResourceUnavailable) 376 | { 377 | if (mHandler) 378 | { 379 | tryUnregReadEvent(); 380 | tryUnregWriteEvent(); 381 | mHandler->onError(this); 382 | } 383 | return true; 384 | } 385 | return false; 386 | } 387 | 388 | EReason Connection::_checkSocketErrors() 389 | { 390 | int err; 391 | EReason reason; 392 | 393 | #ifdef unix 394 | err = errno; 395 | if (EAGAIN == err || EWOULDBLOCK == err) 396 | return Reason_ResourceUnavailable; 397 | 398 | switch (err) 399 | { 400 | case ECONNREFUSED: 401 | reason = Reason_NoSuchPort; 402 | break; 403 | case EPIPE: 404 | reason = Reason_ClientDisconnected; 405 | break; 406 | case ECONNRESET: 407 | reason = Reason_ClientDisconnected; 408 | break; 409 | case ENOBUFS: 410 | reason = Reason_TransmitQueueFull; 411 | break; 412 | default: 413 | reason = Reason_GeneralNetwork; 414 | break; 415 | } 416 | #else 417 | err = WSAGetLastError(); 418 | 419 | if (err == WSAEWOULDBLOCK || err == WSAEINTR) 420 | { 421 | reason = Reason_ResourceUnavailable; 422 | } 423 | else 424 | { 425 | switch (err) 426 | { 427 | case WSAECONNREFUSED: 428 | reason = Reason_NoSuchPort; 429 | break; 430 | case WSAECONNRESET: 431 | reason = Reason_ClientDisconnected; 432 | break; 433 | case WSAECONNABORTED: 434 | reason = Reason_ClientDisconnected; 435 | break; 436 | default: 437 | reason = Reason_GeneralNetwork; 438 | break; 439 | } 440 | } 441 | #endif 442 | 443 | return reason; 444 | } 445 | 446 | NAMESPACE_END // namespace tun 447 | -------------------------------------------------------------------------------- /src/kcp_tunnel.h: -------------------------------------------------------------------------------- 1 | #ifndef __KCPTUNNEL_H__ 2 | #define __KCPTUNNEL_H__ 3 | 4 | #include "fasttun_base.h" 5 | #include "event_poller.h" 6 | #include "cache.h" 7 | #include "udppacket_sender.h" 8 | #include "../kcp/ikcp.h" 9 | 10 | NAMESPACE_BEG(tun) 11 | 12 | //-------------------------------------------------------------------------- 13 | // Kcp参数 14 | struct KcpArg 15 | { 16 | int nodelay; // 是否启用 nodelay模式,0不启用;1启用 17 | int interval; // 协议内部工作的 interval,单位毫秒,比如 10ms或者 20ms 18 | int resend; // 快速重传模式,默认0关闭,可以设置2(2次ACK跨越将会直接重传) 19 | int nc; // 是否关闭流控,默认是0代表不关闭,1代表关闭 20 | int mtu; 21 | }; 22 | 23 | NAMESPACE_BEG(kcpmode) 24 | static KcpArg Normal = {0, 30, 2, 0, 1400,}; 25 | static KcpArg Fast = {0, 20, 2, 1, 1400,}; 26 | static KcpArg Fast2 = {1, 20, 2, 1, 1400,}; 27 | static KcpArg Fast3 = {1, 10, 2, 1, 1400,}; 28 | NAMESPACE_END // namespace kcpmode 29 | //-------------------------------------------------------------------------- 30 | 31 | //-------------------------------------------------------------------------- 32 | // Kcp管道组 33 | struct ITunnel; 34 | struct ITunnelGroup 35 | { 36 | virtual ~ITunnelGroup() {}; 37 | virtual ITunnel* createTunnel(uint32 conv) = 0; 38 | virtual void destroyTunnel(ITunnel *pTunnel) = 0; 39 | 40 | virtual void regOutputNotification(OutputNotificationHandler *p) = 0; 41 | virtual void unregOutputNotification(OutputNotificationHandler *p) = 0; 42 | 43 | virtual int getSockFd() const = 0; 44 | }; 45 | 46 | template 47 | class TunnelGroup : public ITunnelGroup 48 | { 49 | public: 50 | TunnelGroup() : mFd(-1) {} 51 | virtual ~TunnelGroup() {} 52 | 53 | bool create(const char *addr) 54 | { 55 | if (!core::str2Ipv4(addr, mSockAddr)) 56 | { 57 | ErrorPrint("KcpTunnelGroup::create() invalid sockaddr! %s", addr); 58 | return false; 59 | } 60 | 61 | return this->_create(); 62 | } 63 | bool create(const SA *sa, socklen_t salen) 64 | { 65 | memcpy(&mSockAddr, sa, salen); 66 | return this->_create(); 67 | } 68 | bool _create() 69 | { 70 | // create socket 71 | mFd = socket(AF_INET, SOCK_DGRAM, 0); 72 | if (mFd < 0) 73 | return false; 74 | 75 | // set nonblocking 76 | if (!core::setNonblocking(mFd)) 77 | return false; 78 | 79 | return true; 80 | } 81 | 82 | int _processSend(const void *data, size_t datalen) 83 | { 84 | return sendto(mFd, data, datalen, 0, (SA *)&mSockAddr, sizeof(mSockAddr)); 85 | } 86 | 87 | virtual int getSockFd() const 88 | { 89 | return mFd; 90 | } 91 | 92 | protected: 93 | sockaddr_in mSockAddr; 94 | int mFd; 95 | }; 96 | 97 | template <> 98 | class TunnelGroup : public ITunnelGroup 99 | { 100 | public: 101 | TunnelGroup() : mFd(-1) {} 102 | virtual ~TunnelGroup() {} 103 | 104 | bool create(const char *addr) 105 | { 106 | sockaddr_in sockaddr; 107 | if (!core::str2Ipv4(addr, sockaddr)) 108 | { 109 | ErrorPrint("KcpTunnelGroup::create() invalid sockaddr! %s", addr); 110 | return false; 111 | } 112 | return this->create((SA *)&sockaddr, sizeof(sockaddr)); 113 | } 114 | bool create(const SA *sa, socklen_t salen) 115 | { 116 | // create socket 117 | mFd = socket(AF_INET, SOCK_DGRAM, 0); 118 | if (mFd < 0) 119 | return false; 120 | 121 | // set nonblocking 122 | if (!core::setNonblocking(mFd)) 123 | return false; 124 | 125 | // bind local address 126 | if (bind(mFd, sa, salen) < 0) 127 | { 128 | ErrorPrint("KcpTunnelGroup::create() bind local address err! %s", coreStrError()); 129 | return false; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | virtual int getSockFd() const 136 | { 137 | return mFd; 138 | } 139 | 140 | protected: 141 | int mFd; 142 | }; 143 | //-------------------------------------------------------------------------- 144 | 145 | //-------------------------------------------------------------------------- 146 | // Kcp管道 147 | struct KcpTunnelHandler 148 | { 149 | virtual void onRecv(const void *data, size_t datalen) = 0; 150 | }; 151 | 152 | struct ITunnel : public IUdpSender 153 | { 154 | virtual ~ITunnel() {}; 155 | 156 | virtual int send(const void *data, size_t datalen) = 0; 157 | virtual void _output(const void *data, size_t datalen) = 0; 158 | 159 | virtual uint32 getConv() const = 0; 160 | 161 | virtual void setEventHandler(KcpTunnelHandler *h) = 0; 162 | }; 163 | 164 | template 165 | class Tunnel : public ITunnel 166 | { 167 | typedef TunnelGroup MyTunnelGroup; 168 | public: 169 | virtual void _output(const void *data, size_t datalen) 170 | { 171 | mUdpSender.send(data, datalen); 172 | } 173 | 174 | void onRecvPeerAddr(const SA *sa, socklen_t salen) {} 175 | 176 | // IUdpSender 177 | virtual int processSend(const void *data, size_t datalen) 178 | { 179 | return this->mpGroup->_processSend(data, datalen); 180 | } 181 | virtual void regOutputNotification(OutputNotificationHandler *p) 182 | { 183 | mpGroup->regOutputNotification(p); 184 | } 185 | virtual void unregOutputNotification(OutputNotificationHandler *p) 186 | { 187 | mpGroup->unregOutputNotification(p); 188 | } 189 | 190 | protected: 191 | Tunnel(MyTunnelGroup *pGroup) 192 | :mpGroup(pGroup) 193 | ,mUdpSender(this) 194 | { 195 | } 196 | virtual ~Tunnel() {} 197 | 198 | protected: 199 | MyTunnelGroup *mpGroup; 200 | UdpPacketSender mUdpSender; 201 | }; 202 | 203 | template <> 204 | class Tunnel : public ITunnel 205 | { 206 | typedef TunnelGroup MyTunnelGroup; 207 | typedef Cache< Tunnel > MyCache; 208 | public: 209 | virtual void _output(const void *data, size_t datalen) 210 | { 211 | if (this->mAddrSettled) 212 | { 213 | this->mCache->flushAll(); 214 | mUdpSender.send(data, datalen); 215 | } 216 | else 217 | { 218 | this->mCache->cache(data, datalen); 219 | } 220 | } 221 | 222 | void onRecvPeerAddr(const SA *sa, socklen_t salen) 223 | { 224 | memcpy(&mSockAddr, sa, salen); 225 | mAddrSettled = true; 226 | } 227 | 228 | bool flush(const void *data, size_t datalen) 229 | { 230 | mUdpSender.send(data, datalen); 231 | return true; 232 | } 233 | 234 | // IUdpSender 235 | virtual int processSend(const void *data, size_t datalen) 236 | { 237 | return sendto(mpGroup->getSockFd(), data, datalen, 0, 238 | (SA *)&this->mSockAddr, sizeof(this->mSockAddr)); 239 | } 240 | virtual void regOutputNotification(OutputNotificationHandler *p) 241 | { 242 | mpGroup->regOutputNotification(p); 243 | } 244 | virtual void unregOutputNotification(OutputNotificationHandler *p) 245 | { 246 | mpGroup->unregOutputNotification(p); 247 | } 248 | 249 | protected: 250 | Tunnel(MyTunnelGroup *pGroup) 251 | :mpGroup(pGroup) 252 | ,mAddrSettled(false) 253 | ,mUdpSender(this) 254 | { 255 | this->mCache = new MyCache(this, &Tunnel::flush); 256 | } 257 | virtual ~Tunnel() 258 | { 259 | delete this->mCache; 260 | } 261 | 262 | protected: 263 | MyTunnelGroup *mpGroup; 264 | 265 | bool mAddrSettled; 266 | sockaddr_in mSockAddr; 267 | 268 | MyCache *mCache; 269 | UdpPacketSender mUdpSender; 270 | }; 271 | 272 | template 273 | class KcpTunnel : public Tunnel 274 | { 275 | typedef TunnelGroup MyTunnelGroup; 276 | typedef Cache< KcpTunnel > SndCache; 277 | public: 278 | KcpTunnel(MyTunnelGroup *pGroup) 279 | :Tunnel(pGroup) 280 | ,mKcpCb(NULL) 281 | ,mHandler(NULL) 282 | ,mConv(0) 283 | ,mSentCount(0) 284 | ,mRecvCount(0) 285 | { 286 | this->mSndCache = new SndCache(this, &KcpTunnel::flushSndBuf); 287 | } 288 | 289 | virtual ~KcpTunnel(); 290 | 291 | bool create(uint32 conv, const KcpArg &arg); 292 | void shutdown(); 293 | 294 | virtual int send(const void *data, size_t datalen); 295 | virtual uint32 getConv() const 296 | { 297 | return mConv; 298 | } 299 | virtual void setEventHandler(KcpTunnelHandler *h) 300 | { 301 | mHandler = h; 302 | } 303 | 304 | bool input(const void *data, size_t datalen); 305 | uint32 update(uint32 current); 306 | 307 | bool _flushAll(); 308 | bool flushSndBuf(const void *data, size_t datalen); 309 | bool _canFlush() const; 310 | 311 | private: 312 | ikcpcb *mKcpCb; 313 | KcpTunnelHandler *mHandler; 314 | uint32 mConv; 315 | 316 | int mSentCount; 317 | int mRecvCount; 318 | 319 | SndCache *mSndCache; 320 | }; 321 | //-------------------------------------------------------------------------- 322 | 323 | //-------------------------------------------------------------------------- 324 | // Kcp管道组(最终实现) 325 | template 326 | class KcpTunnelGroup : public InputNotificationHandler 327 | , public OutputNotificationHandler 328 | , public TunnelGroup 329 | { 330 | typedef TunnelGroup Supper; 331 | typedef KcpTunnel Tun; 332 | public: 333 | KcpTunnelGroup(EventPoller *poller) 334 | :Supper() 335 | ,mEventPoller(poller) 336 | ,mbRegForWrite(false) 337 | ,mOutputNotifyList() 338 | ,mTunnels() 339 | ,mKcpArg(kcpmode::Fast3) 340 | { 341 | } 342 | 343 | virtual ~KcpTunnelGroup(); 344 | 345 | bool create(const char *addr); 346 | bool create(const SA* sa, socklen_t salen); 347 | bool _create(); 348 | void shutdown(); 349 | 350 | int _output(const void *data, size_t datalen); 351 | 352 | virtual ITunnel* createTunnel(uint32 conv); 353 | virtual void destroyTunnel(ITunnel *pTunnel); 354 | 355 | virtual void regOutputNotification(OutputNotificationHandler *p); 356 | virtual void unregOutputNotification(OutputNotificationHandler *p); 357 | 358 | uint32 update(); 359 | 360 | // InputNotificationHandler 361 | virtual int handleInputNotification(int fd); 362 | 363 | // OutputNotificationHandler 364 | virtual int handleOutputNotification(int fd); 365 | 366 | inline void setKcpMode(const KcpArg &mode) 367 | { 368 | mKcpArg = mode; 369 | } 370 | 371 | private: 372 | void tryRegWriteEvent() 373 | { 374 | if (!mbRegForWrite) 375 | { 376 | mbRegForWrite = true; 377 | mEventPoller->registerForWrite(this->getSockFd(), this); 378 | } 379 | } 380 | 381 | void tryUnregWriteEvent() 382 | { 383 | if (mbRegForWrite) 384 | { 385 | mbRegForWrite = false; 386 | mEventPoller->deregisterForWrite(this->getSockFd()); 387 | } 388 | } 389 | 390 | private: 391 | typedef std::map Tunnels; 392 | typedef std::set OutputNotifyList; 393 | 394 | EventPoller *mEventPoller; 395 | 396 | bool mbRegForWrite; 397 | OutputNotifyList mOutputNotifyList; 398 | 399 | Tunnels mTunnels; 400 | KcpArg mKcpArg; 401 | }; 402 | //-------------------------------------------------------------------------- 403 | 404 | NAMESPACE_END // namespace tun 405 | 406 | #include "kcp_tunnel.inl" 407 | 408 | #endif // __KCPTUNNEL_H__ 409 | -------------------------------------------------------------------------------- /src/client.cpp: -------------------------------------------------------------------------------- 1 | #include "fasttun_base.h" 2 | #include "select_poller.h" 3 | #include "epoll_poller.h" 4 | #include "listener.h" 5 | #include "connection.h" 6 | #include "kcp_tunnel.h" 7 | #include "fast_connection.h" 8 | 9 | using namespace tun; 10 | 11 | core::Timers tun::gTimer; 12 | 13 | typedef KcpTunnelGroup MyTunnelGroup; 14 | static MyTunnelGroup *gTunnelManager = NULL; 15 | 16 | static sockaddr_in ListenAddr; 17 | static sockaddr_in RemoteAddr; 18 | static sockaddr_in KcpRemoteAddr; 19 | 20 | //-------------------------------------------------------------------------- 21 | class ClientBridge : public Connection::Handler, public FastConnection::Handler 22 | { 23 | public: 24 | struct Handler 25 | { 26 | virtual void onIntConnDisconnected(ClientBridge *pBridge) = 0; 27 | virtual void onIntConnError(ClientBridge *pBridge) = 0; 28 | }; 29 | 30 | ClientBridge(EventPoller *poller, Handler *l) 31 | :mEventPoller(poller) 32 | ,mpHandler(l) 33 | ,mIntConn(poller) 34 | ,mExtConn(poller, gTunnelManager) 35 | ,mLastExtConnTime(0) 36 | {} 37 | 38 | virtual ~ClientBridge() 39 | { 40 | shutdown(); 41 | } 42 | 43 | bool acceptConnection(int connfd) 44 | { 45 | if (!mIntConn.acceptConnection(connfd)) 46 | { 47 | mIntConn.shutdown(); 48 | return false; 49 | } 50 | mIntConn.setEventHandler(this); 51 | 52 | mLastExtConnTime = core::getClock(); 53 | mExtConn.setEventHandler(this); 54 | if (!mExtConn.connect((const SA *)&RemoteAddr, sizeof(RemoteAddr))) 55 | { 56 | mIntConn.shutdown(); 57 | return false; 58 | } 59 | 60 | return true; 61 | } 62 | 63 | void shutdown() 64 | { 65 | mIntConn.shutdown(); 66 | mExtConn.shutdown(); 67 | } 68 | 69 | // Connection::Handler 70 | virtual void onConnected(FastConnection *pConn) 71 | { 72 | } 73 | 74 | virtual void onDisconnected(Connection *pConn) 75 | { 76 | if (mpHandler) 77 | { 78 | mpHandler->onIntConnDisconnected(this); 79 | mIntConn.shutdown(); 80 | } 81 | } 82 | 83 | virtual void onError(Connection *pConn) 84 | { 85 | if (mpHandler) 86 | { 87 | mpHandler->onIntConnError(this); 88 | mIntConn.shutdown(); 89 | } 90 | } 91 | 92 | virtual void onRecv(Connection *pConn, const void *data, size_t datalen) 93 | { 94 | mExtConn.send(data, datalen); 95 | if (!mExtConn.isConnected()) 96 | _reconnectExternal(); 97 | } 98 | 99 | // FastConnection::Handler 100 | virtual void onDisconnected(FastConnection *pConn) 101 | { 102 | _reconnectExternal(); 103 | } 104 | virtual void onError(FastConnection *pConn) 105 | { 106 | _reconnectExternal(); 107 | WarningPrint("a fast connection ocur an error! reason:%s", coreStrError()); 108 | } 109 | virtual void onCreateKcpTunnelFailed(FastConnection *pConn) 110 | { 111 | _reconnectExternal(); 112 | WarningPrint("create fast connection faild!"); 113 | } 114 | 115 | virtual void onRecv(FastConnection *pConn, const void *data, size_t datalen) 116 | { 117 | mIntConn.send(data, datalen); 118 | } 119 | 120 | void _reconnectExternal() 121 | { 122 | ulong curtick = core::getClock(); 123 | if (curtick > mLastExtConnTime+10000) 124 | { 125 | mLastExtConnTime = curtick; 126 | mExtConn.connect((const SA *)&RemoteAddr, sizeof(RemoteAddr)); 127 | } 128 | } 129 | 130 | private: 131 | EventPoller *mEventPoller; 132 | Handler *mpHandler; 133 | 134 | Connection mIntConn; 135 | FastConnection mExtConn; 136 | 137 | ulong mLastExtConnTime; 138 | }; 139 | //-------------------------------------------------------------------------- 140 | 141 | //-------------------------------------------------------------------------- 142 | class Client : public Listener::Handler, public ClientBridge::Handler 143 | { 144 | public: 145 | Client(EventPoller *poller) 146 | :Listener::Handler() 147 | ,mEventPoller(poller) 148 | ,mListener(poller) 149 | ,mBridges() 150 | ,mShutedBridges() 151 | { 152 | } 153 | 154 | virtual ~Client() 155 | { 156 | } 157 | 158 | bool create(const SA *sa, socklen_t salen) 159 | { 160 | if (!mListener.initialise(sa, salen)) 161 | { 162 | ErrorPrint("create listener failed."); 163 | return false; 164 | } 165 | mListener.setEventHandler(this); 166 | 167 | return true; 168 | } 169 | 170 | void finalise() 171 | { 172 | mListener.finalise(); 173 | 174 | update(); 175 | BridgeList::iterator it = mBridges.begin(); 176 | for (; it != mBridges.end(); ++it) 177 | { 178 | ClientBridge *bridge = *it; 179 | if (bridge) 180 | { 181 | bridge->shutdown(); 182 | delete bridge; 183 | } 184 | } 185 | mBridges.clear(); 186 | } 187 | 188 | // call it ervery frame 189 | void update() 190 | { 191 | BridgeList::iterator it = mShutedBridges.begin(); 192 | for (; it != mShutedBridges.end(); ++it) 193 | { 194 | (*it)->shutdown(); 195 | delete *it; 196 | } 197 | mShutedBridges.clear(); 198 | } 199 | 200 | virtual void onAccept(int connfd) 201 | { 202 | ClientBridge *bridge = new ClientBridge(mEventPoller, this); 203 | if (!bridge->acceptConnection(connfd)) 204 | { 205 | delete bridge; 206 | return; 207 | } 208 | 209 | mBridges.insert(bridge); 210 | DebugPrint("a connection createted! cursize:%u", mBridges.size()); 211 | } 212 | 213 | virtual void onIntConnDisconnected(ClientBridge *pBridge) 214 | { 215 | onBridgeShut(pBridge); 216 | DebugPrint("a connection closed! cursize:%u", mBridges.size()); 217 | } 218 | 219 | virtual void onIntConnError(ClientBridge *pBridge) 220 | { 221 | onBridgeShut(pBridge); 222 | WarningPrint("a connection occur error! cursize:%u reason:%s", mBridges.size(), coreStrError()); 223 | } 224 | 225 | private: 226 | void onBridgeShut(ClientBridge *pBridge) 227 | { 228 | BridgeList::iterator it = mBridges.find(pBridge); 229 | if (it != mBridges.end()) 230 | { 231 | mBridges.erase(it); 232 | } 233 | 234 | mShutedBridges.insert(pBridge); 235 | } 236 | 237 | private: 238 | typedef std::set BridgeList; 239 | 240 | EventPoller *mEventPoller; 241 | Listener mListener; 242 | 243 | BridgeList mBridges; 244 | BridgeList mShutedBridges; 245 | }; 246 | //-------------------------------------------------------------------------- 247 | 248 | static bool s_continueMainLoop = true; 249 | void sigHandler(int signo) 250 | { 251 | switch (signo) 252 | { 253 | case SIGPIPE: 254 | { 255 | WarningPrint("broken pipe!"); 256 | } 257 | break; 258 | case SIGINT: 259 | { 260 | InfoPrint("catch SIGINT!"); 261 | s_continueMainLoop = false; 262 | } 263 | break; 264 | case SIGQUIT: 265 | { 266 | InfoPrint("catch SIGQUIT!"); 267 | s_continueMainLoop = false; 268 | } 269 | break; 270 | case SIGKILL: 271 | { 272 | InfoPrint("catch SIGKILL!"); 273 | s_continueMainLoop = false; 274 | } 275 | break; 276 | case SIGTERM: 277 | { 278 | InfoPrint("catch SIGTERM!"); 279 | s_continueMainLoop = false; 280 | } 281 | break; 282 | default: 283 | break; 284 | } 285 | } 286 | 287 | int main(int argc, char *argv[]) 288 | { 289 | // parse parameter 290 | int pidFlags = 0; 291 | bool bVerbose = false; 292 | const char *confPath = NULL; 293 | const char *listenAddr = NULL; 294 | const char *remoteAddr = NULL; 295 | const char *kcpRemoteAddr = NULL; 296 | const char *pidPath = NULL; 297 | 298 | int opt = 0; 299 | while ((opt = getopt(argc, argv, "f:c:l:r:v")) != -1) 300 | { 301 | switch (opt) 302 | { 303 | case 'c': 304 | confPath = optarg; 305 | break; 306 | case 'l': 307 | listenAddr = optarg; 308 | break; 309 | case 'r': 310 | remoteAddr = optarg; 311 | break; 312 | case 'u': 313 | kcpRemoteAddr = optarg; 314 | break; 315 | case 'f': 316 | pidFlags = 1; 317 | pidPath = optarg; 318 | break; 319 | case 'v': 320 | bVerbose = true; 321 | break; 322 | default: 323 | break; 324 | } 325 | } 326 | 327 | // daemoniize 328 | int logLevel = InfoLog | WarningLog | ErrorLog | EmphasisLog; 329 | if (bVerbose) 330 | logLevel |= DebugLog; 331 | 332 | if (pidFlags) 333 | { 334 | daemonize(pidPath); 335 | 336 | if (log_initialise(logLevel) != 0) 337 | { 338 | fprintf(stderr, "init log failed!"); 339 | exit(1); 340 | } 341 | 342 | log_reg_filelog("log", "tuncli-", "/var/log", "tuncli-old-", "/var/log"); 343 | } 344 | else 345 | { 346 | if (log_initialise(logLevel) != 0) 347 | { 348 | fprintf(stderr, "init log failed!"); 349 | exit(1); 350 | } 351 | 352 | log_reg_filelog("log", "tuncli-", "/tmp", "tuncli-old-", "/tmp"); 353 | log_reg_console(); 354 | } 355 | 356 | if (argc == 1) 357 | { 358 | confPath = DEFAULT_CONF_PATH; 359 | } 360 | if (confPath) 361 | { 362 | Ini ini(confPath); 363 | static std::string s_listenAddr = ini.getString("local", "listen", ""); 364 | static std::string s_remoteAddr = ini.getString("local", "remote", ""); 365 | static std::string s_kcpRemoteAddr = ini.getString("local", "kcpremote", s_remoteAddr.c_str()); 366 | if (s_listenAddr != "") 367 | listenAddr = s_listenAddr.c_str(); 368 | if (s_remoteAddr != "") 369 | remoteAddr = s_remoteAddr.c_str(); 370 | if (s_kcpRemoteAddr != "") 371 | kcpRemoteAddr = s_kcpRemoteAddr.c_str(); 372 | } 373 | 374 | if (NULL == listenAddr || NULL == remoteAddr || NULL == kcpRemoteAddr) 375 | { 376 | fprintf(stderr, "no argument assigned or parse argument failed!\n"); 377 | log_finalise(); 378 | exit(EXIT_FAILURE); 379 | } 380 | if (!core::str2Ipv4(listenAddr, ListenAddr) || 381 | !core::str2Ipv4(remoteAddr, RemoteAddr) || 382 | !core::str2Ipv4(kcpRemoteAddr, KcpRemoteAddr)) 383 | { 384 | ErrorPrint("invalid socket address!"); 385 | log_finalise(); 386 | exit(EXIT_FAILURE); 387 | } 388 | 389 | // create event poller 390 | #ifdef HAS_EPOLL 391 | EventPoller *netPoller = new EpollPoller(); 392 | #else 393 | EventPoller *netPoller = new SelectPoller(); 394 | #endif 395 | 396 | // kcp tunnel manager 397 | gTunnelManager = new MyTunnelGroup(netPoller); 398 | if (!gTunnelManager->create(kcpRemoteAddr)) 399 | { 400 | ErrorPrint("initialise Tunnel Manager error!"); 401 | delete netPoller; 402 | log_finalise(); 403 | exit(EXIT_FAILURE); 404 | } 405 | 406 | // create client 407 | Client cli(netPoller); 408 | if (!cli.create((const SA *)&ListenAddr, sizeof(ListenAddr))) 409 | { 410 | ErrorPrint("create client error!"); 411 | gTunnelManager->shutdown(); 412 | delete gTunnelManager; 413 | delete netPoller; 414 | log_finalise(); 415 | exit(EXIT_FAILURE); 416 | } 417 | 418 | struct sigaction newAct; 419 | newAct.sa_handler = sigHandler; 420 | sigemptyset(&newAct.sa_mask); 421 | newAct.sa_flags = 0; 422 | 423 | sigaction(SIGPIPE, &newAct, NULL); 424 | 425 | sigaction(SIGINT, &newAct, NULL); 426 | sigaction(SIGQUIT, &newAct, NULL); 427 | 428 | // sigaction(SIGKILL, &newAct, NULL); 429 | sigaction(SIGTERM, &newAct, NULL); 430 | 431 | static const uint32 MAX_WAIT = 60000; 432 | double maxWait = 0; 433 | uint32 curClock = 0, nextKcpUpdateInterval = 0, nextTimerCheckInterval = 0; 434 | DebugPrint("Enter Main Loop..."); 435 | while (s_continueMainLoop) 436 | { 437 | curClock = core::getClock(); 438 | 439 | netPoller->processPendingEvents(maxWait); 440 | 441 | nextKcpUpdateInterval = gTunnelManager->update(); 442 | 443 | gTimer.process(curClock); 444 | nextTimerCheckInterval = gTimer.nextExp(curClock); 445 | if (0 == nextTimerCheckInterval) 446 | nextTimerCheckInterval = MAX_WAIT; 447 | 448 | cli.update(); 449 | 450 | maxWait = min(nextKcpUpdateInterval, nextTimerCheckInterval); 451 | maxWait *= 0.001f; 452 | } 453 | DebugPrint("Leave Main Loop..."); 454 | 455 | // finalise 456 | cli.finalise(); 457 | 458 | gTunnelManager->shutdown(); 459 | delete gTunnelManager; 460 | 461 | delete netPoller; 462 | 463 | // uninit log 464 | DebugPrint("Exit Fasttun!"); 465 | log_finalise(); 466 | exit(0); 467 | } 468 | -------------------------------------------------------------------------------- /kcp/ikcp.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #ifndef __IKCP_H__ 13 | #define __IKCP_H__ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | //===================================================================== 21 | // 32BIT INTEGER DEFINITION 22 | //===================================================================== 23 | #ifndef __INTEGER_32_BITS__ 24 | #define __INTEGER_32_BITS__ 25 | #if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ 26 | defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ 27 | defined(_M_AMD64) 28 | typedef unsigned int ISTDUINT32; 29 | typedef int ISTDINT32; 30 | #elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ 31 | defined(__i386) || defined(_M_X86) 32 | typedef unsigned long ISTDUINT32; 33 | typedef long ISTDINT32; 34 | #elif defined(__MACOS__) 35 | typedef UInt32 ISTDUINT32; 36 | typedef SInt32 ISTDINT32; 37 | #elif defined(__APPLE__) && defined(__MACH__) 38 | #include 39 | typedef u_int32_t ISTDUINT32; 40 | typedef int32_t ISTDINT32; 41 | #elif defined(__BEOS__) 42 | #include 43 | typedef u_int32_t ISTDUINT32; 44 | typedef int32_t ISTDINT32; 45 | #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) 46 | typedef unsigned __int32 ISTDUINT32; 47 | typedef __int32 ISTDINT32; 48 | #elif defined(__GNUC__) 49 | #include 50 | typedef uint32_t ISTDUINT32; 51 | typedef int32_t ISTDINT32; 52 | #else 53 | typedef unsigned long ISTDUINT32; 54 | typedef long ISTDINT32; 55 | #endif 56 | #endif 57 | 58 | 59 | //===================================================================== 60 | // Integer Definition 61 | //===================================================================== 62 | #ifndef __IINT8_DEFINED 63 | #define __IINT8_DEFINED 64 | typedef char IINT8; 65 | #endif 66 | 67 | #ifndef __IUINT8_DEFINED 68 | #define __IUINT8_DEFINED 69 | typedef unsigned char IUINT8; 70 | #endif 71 | 72 | #ifndef __IUINT16_DEFINED 73 | #define __IUINT16_DEFINED 74 | typedef unsigned short IUINT16; 75 | #endif 76 | 77 | #ifndef __IINT16_DEFINED 78 | #define __IINT16_DEFINED 79 | typedef short IINT16; 80 | #endif 81 | 82 | #ifndef __IINT32_DEFINED 83 | #define __IINT32_DEFINED 84 | typedef ISTDINT32 IINT32; 85 | #endif 86 | 87 | #ifndef __IUINT32_DEFINED 88 | #define __IUINT32_DEFINED 89 | typedef ISTDUINT32 IUINT32; 90 | #endif 91 | 92 | #ifndef __IINT64_DEFINED 93 | #define __IINT64_DEFINED 94 | #if defined(_MSC_VER) || defined(__BORLANDC__) 95 | typedef __int64 IINT64; 96 | #else 97 | typedef long long IINT64; 98 | #endif 99 | #endif 100 | 101 | #ifndef __IUINT64_DEFINED 102 | #define __IUINT64_DEFINED 103 | #if defined(_MSC_VER) || defined(__BORLANDC__) 104 | typedef unsigned __int64 IUINT64; 105 | #else 106 | typedef unsigned long long IUINT64; 107 | #endif 108 | #endif 109 | 110 | #ifndef INLINE 111 | #if defined(__GNUC__) 112 | 113 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 114 | #define INLINE __inline__ __attribute__((always_inline)) 115 | #else 116 | #define INLINE __inline__ 117 | #endif 118 | 119 | #elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) 120 | #define INLINE __inline 121 | #else 122 | #define INLINE 123 | #endif 124 | #endif 125 | 126 | #ifndef inline 127 | #define inline INLINE 128 | #endif 129 | 130 | 131 | //===================================================================== 132 | // QUEUE DEFINITION 133 | //===================================================================== 134 | #ifndef __IQUEUE_DEF__ 135 | #define __IQUEUE_DEF__ 136 | 137 | struct IQUEUEHEAD { 138 | struct IQUEUEHEAD *next, *prev; 139 | }; 140 | 141 | typedef struct IQUEUEHEAD iqueue_head; 142 | 143 | 144 | //--------------------------------------------------------------------- 145 | // queue init 146 | //--------------------------------------------------------------------- 147 | #define IQUEUE_HEAD_INIT(name) { &(name), &(name) } 148 | #define IQUEUE_HEAD(name) \ 149 | struct IQUEUEHEAD name = IQUEUE_HEAD_INIT(name) 150 | 151 | #define IQUEUE_INIT(ptr) ( \ 152 | (ptr)->next = (ptr), (ptr)->prev = (ptr)) 153 | 154 | #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 155 | 156 | #define ICONTAINEROF(ptr, type, member) ( \ 157 | (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) 158 | 159 | #define IQUEUE_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) 160 | 161 | 162 | //--------------------------------------------------------------------- 163 | // queue operation 164 | //--------------------------------------------------------------------- 165 | #define IQUEUE_ADD(node, head) ( \ 166 | (node)->prev = (head), (node)->next = (head)->next, \ 167 | (head)->next->prev = (node), (head)->next = (node)) 168 | 169 | #define IQUEUE_ADD_TAIL(node, head) ( \ 170 | (node)->prev = (head)->prev, (node)->next = (head), \ 171 | (head)->prev->next = (node), (head)->prev = (node)) 172 | 173 | #define IQUEUE_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) 174 | 175 | #define IQUEUE_DEL(entry) (\ 176 | (entry)->next->prev = (entry)->prev, \ 177 | (entry)->prev->next = (entry)->next, \ 178 | (entry)->next = 0, (entry)->prev = 0) 179 | 180 | #define IQUEUE_DEL_INIT(entry) do { \ 181 | IQUEUE_DEL(entry); IQUEUE_INIT(entry); } while (0) 182 | 183 | #define IQUEUE_IS_EMPTY(entry) ((entry) == (entry)->next) 184 | 185 | #define iqueue_init IQUEUE_INIT 186 | #define iqueue_entry IQUEUE_ENTRY 187 | #define iqueue_add IQUEUE_ADD 188 | #define iqueue_add_tail IQUEUE_ADD_TAIL 189 | #define iqueue_del IQUEUE_DEL 190 | #define iqueue_del_init IQUEUE_DEL_INIT 191 | #define iqueue_is_empty IQUEUE_IS_EMPTY 192 | 193 | #define IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) \ 194 | for ((iterator) = iqueue_entry((head)->next, TYPE, MEMBER); \ 195 | &((iterator)->MEMBER) != (head); \ 196 | (iterator) = iqueue_entry((iterator)->MEMBER.next, TYPE, MEMBER)) 197 | 198 | #define iqueue_foreach(iterator, head, TYPE, MEMBER) \ 199 | IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) 200 | 201 | #define iqueue_foreach_entry(pos, head) \ 202 | for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) 203 | 204 | 205 | #define __iqueue_splice(list, head) do { \ 206 | iqueue_head *first = (list)->next, *last = (list)->prev; \ 207 | iqueue_head *at = (head)->next; \ 208 | (first)->prev = (head), (head)->next = (first); \ 209 | (last)->next = (at), (at)->prev = (last); } while (0) 210 | 211 | #define iqueue_splice(list, head) do { \ 212 | if (!iqueue_is_empty(list)) __iqueue_splice(list, head); } while (0) 213 | 214 | #define iqueue_splice_init(list, head) do { \ 215 | iqueue_splice(list, head); iqueue_init(list); } while (0) 216 | 217 | 218 | #ifdef _MSC_VER 219 | #pragma warning(disable:4311) 220 | #pragma warning(disable:4312) 221 | #pragma warning(disable:4996) 222 | #endif 223 | 224 | #endif 225 | 226 | 227 | //--------------------------------------------------------------------- 228 | // WORD ORDER 229 | //--------------------------------------------------------------------- 230 | #ifndef IWORDS_BIG_ENDIAN 231 | #ifdef _BIG_ENDIAN_ 232 | #if _BIG_ENDIAN_ 233 | #define IWORDS_BIG_ENDIAN 1 234 | #endif 235 | #endif 236 | #ifndef IWORDS_BIG_ENDIAN 237 | #if defined(__hppa__) || \ 238 | defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ 239 | (defined(__MIPS__) && defined(__MISPEB__)) || \ 240 | defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ 241 | defined(__sparc__) || defined(__powerpc__) || \ 242 | defined(__mc68000__) || defined(__s390x__) || defined(__s390__) 243 | #define IWORDS_BIG_ENDIAN 1 244 | #endif 245 | #endif 246 | #ifndef IWORDS_BIG_ENDIAN 247 | #define IWORDS_BIG_ENDIAN 0 248 | #endif 249 | #endif 250 | 251 | 252 | 253 | //===================================================================== 254 | // SEGMENT 255 | //===================================================================== 256 | struct IKCPSEG 257 | { 258 | struct IQUEUEHEAD node; 259 | IUINT32 conv; 260 | IUINT32 cmd; 261 | IUINT32 frg; 262 | IUINT32 wnd; 263 | IUINT32 ts; 264 | IUINT32 sn; 265 | IUINT32 una; 266 | IUINT32 len; 267 | IUINT32 resendts; 268 | IUINT32 rto; 269 | IUINT32 fastack; 270 | IUINT32 xmit; 271 | char data[1]; 272 | }; 273 | 274 | 275 | //--------------------------------------------------------------------- 276 | // IKCPCB 277 | //--------------------------------------------------------------------- 278 | struct IKCPCB 279 | { 280 | IUINT32 conv, mtu, mss, state; 281 | IUINT32 snd_una, snd_nxt, rcv_nxt; 282 | IUINT32 ts_recent, ts_lastack, ssthresh; 283 | IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; 284 | IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; 285 | IUINT32 current, interval, ts_flush, xmit; 286 | IUINT32 nrcv_buf, nsnd_buf; 287 | IUINT32 nrcv_que, nsnd_que; 288 | IUINT32 nodelay, updated; 289 | IUINT32 ts_probe, probe_wait; 290 | IUINT32 dead_link, incr; 291 | struct IQUEUEHEAD snd_queue; 292 | struct IQUEUEHEAD rcv_queue; 293 | struct IQUEUEHEAD snd_buf; 294 | struct IQUEUEHEAD rcv_buf; 295 | IUINT32 *acklist; 296 | IUINT32 ackcount; 297 | IUINT32 ackblock; 298 | void *user; 299 | char *buffer; 300 | int fastresend; 301 | int nocwnd; 302 | int logmask; 303 | int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); 304 | void (*writelog)(const char *log, struct IKCPCB *kcp, void *user); 305 | }; 306 | 307 | 308 | typedef struct IKCPCB ikcpcb; 309 | 310 | #define IKCP_LOG_OUTPUT 1 311 | #define IKCP_LOG_INPUT 2 312 | #define IKCP_LOG_SEND 4 313 | #define IKCP_LOG_RECV 8 314 | #define IKCP_LOG_IN_DATA 16 315 | #define IKCP_LOG_IN_ACK 32 316 | #define IKCP_LOG_IN_PROBE 64 317 | #define IKCP_LOG_IN_WINS 128 318 | #define IKCP_LOG_OUT_DATA 256 319 | #define IKCP_LOG_OUT_ACK 512 320 | #define IKCP_LOG_OUT_PROBE 1024 321 | #define IKCP_LOG_OUT_WINS 2048 322 | 323 | #ifdef __cplusplus 324 | extern "C" { 325 | #endif 326 | 327 | //--------------------------------------------------------------------- 328 | // interface 329 | //--------------------------------------------------------------------- 330 | 331 | // create a new kcp control object, 'conv' must equal in two endpoint 332 | // from the same connection. 'user' will be passed to the output callback 333 | // output callback can be setup like this: 'kcp->output = my_udp_output' 334 | ikcpcb* ikcp_create(IUINT32 conv, void *user); 335 | 336 | // release kcp control object 337 | void ikcp_release(ikcpcb *kcp); 338 | 339 | // user/upper level recv: returns size, returns below zero for EAGAIN 340 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len); 341 | 342 | // user/upper level send, returns below zero for error 343 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len); 344 | 345 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 346 | // ikcp_check when to call it again (without ikcp_input/_send calling). 347 | // 'current' - current timestamp in millisec. 348 | void ikcp_update(ikcpcb *kcp, IUINT32 current); 349 | 350 | // Determine when should you invoke ikcp_update: 351 | // returns when you should invoke ikcp_update in millisec, if there 352 | // is no ikcp_input/_send calling. you can call ikcp_update in that 353 | // time, instead of call update repeatly. 354 | // Important to reduce unnacessary ikcp_update invoking. use it to 355 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 356 | // or optimize ikcp_update when handling massive kcp connections) 357 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); 358 | 359 | // Get conv from a udp packet. 360 | // you can use this func to find out one packet should bind to which ikcpcb obj. 361 | // return 1 if get conv success. 362 | // return 0 if get conv error. 363 | int ikcp_get_conv(const char *data, long size, IUINT32* conv_out); 364 | 365 | // when you received a low level packet (eg. UDP packet), call it 366 | int ikcp_input(ikcpcb *kcp, const char *data, long size); 367 | 368 | // flush pending data 369 | void ikcp_flush(ikcpcb *kcp); 370 | 371 | // check the size of next message in the recv queue 372 | int ikcp_peeksize(const ikcpcb *kcp); 373 | 374 | // change MTU size, default is 1400 375 | int ikcp_setmtu(ikcpcb *kcp, int mtu); 376 | 377 | // set maximum window size: sndwnd=32, rcvwnd=32 by default 378 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); 379 | 380 | // get how many packet is waiting to be sent 381 | int ikcp_waitsnd(const ikcpcb *kcp); 382 | 383 | // fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) 384 | // nodelay: 0:disable(default), 1:enable 385 | // interval: internal update timer interval in millisec, default is 100ms 386 | // resend: 0:disable fast resend(default), 1:enable fast resend 387 | // nc: 0:normal congestion control(default), 1:disable congestion control 388 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); 389 | 390 | int ikcp_rcvbuf_count(const ikcpcb *kcp); 391 | int ikcp_sndbuf_count(const ikcpcb *kcp); 392 | 393 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...); 394 | 395 | // setup allocator 396 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)); 397 | 398 | 399 | #ifdef __cplusplus 400 | } 401 | #endif 402 | 403 | #endif 404 | 405 | 406 | -------------------------------------------------------------------------------- /src/server.cpp: -------------------------------------------------------------------------------- 1 | #include "fasttun_base.h" 2 | #include "select_poller.h" 3 | #include "epoll_poller.h" 4 | #include "listener.h" 5 | #include "connection.h" 6 | #include "kcp_tunnel.h" 7 | #include "fast_connection.h" 8 | #include "cache.h" 9 | 10 | using namespace tun; 11 | 12 | core::Timers tun::gTimer; 13 | 14 | typedef KcpTunnelGroup MyTunnelGroup; 15 | static MyTunnelGroup *gTunnelManager = NULL; 16 | 17 | static sockaddr_in ListenAddr, KcpListenAddr; 18 | static sockaddr_in ConnectAddr; 19 | 20 | //-------------------------------------------------------------------------- 21 | class ServerBridge : public Connection::Handler 22 | , public FastConnection::Handler 23 | , public TimerHandler 24 | { 25 | static const uint32 CONNCHECK_INTERVAL = 30000; 26 | 27 | public: 28 | struct Handler 29 | { 30 | virtual void onExtConnDisconnected(ServerBridge *pBridge) = 0; 31 | virtual void onExtConnError(ServerBridge *pBridge) = 0; 32 | }; 33 | 34 | ServerBridge(EventPoller *poller, Handler *h) 35 | :mEventPoller(poller) 36 | ,mpHandler(h) 37 | ,mIntConn(poller) 38 | ,mExtConn(poller, gTunnelManager) 39 | ,mCache(NULL) 40 | ,mLastExtConnTime(0) 41 | ,mHeartBeatTimer() 42 | ,mConnCheckTimer() 43 | { 44 | mCache = new MyCache(this, &ServerBridge::flush); 45 | } 46 | 47 | virtual ~ServerBridge() 48 | { 49 | delete mCache; 50 | } 51 | 52 | bool acceptConnection(int connfd) 53 | { 54 | if (!mExtConn.acceptConnection(connfd)) 55 | { 56 | return false; 57 | } 58 | mExtConn.setEventHandler(this); 59 | 60 | mLastExtConnTime = core::getClock(); 61 | mIntConn.setEventHandler(this); 62 | if (!mIntConn.connect((const SA *)&ConnectAddr, sizeof(ConnectAddr))) 63 | { 64 | mExtConn.shutdown(); 65 | return false; 66 | } 67 | 68 | uint32 curClock = core::getClock(); 69 | mHeartBeatTimer = gTimer.add(curClock+HeartBeatRecord::HEARTBEAT_INTERVAL, 70 | HeartBeatRecord::HEARTBEAT_INTERVAL, 71 | this, NULL); 72 | mConnCheckTimer = gTimer.add(curClock+CONNCHECK_INTERVAL, 73 | CONNCHECK_INTERVAL, 74 | this, NULL); 75 | 76 | return true; 77 | } 78 | 79 | void shutdown() 80 | { 81 | mHeartBeatTimer.cancel(); 82 | mConnCheckTimer.cancel(); 83 | 84 | mExtConn.shutdown(); 85 | mIntConn.shutdown(); 86 | } 87 | 88 | // Connection::Handler 89 | virtual void onConnected(Connection *pConn) 90 | { 91 | _flushAll(); 92 | } 93 | virtual void onDisconnected(Connection *pConn) 94 | { 95 | _reconnectInternal(); 96 | } 97 | 98 | virtual void onRecv(Connection *pConn, const void *data, size_t datalen) 99 | { 100 | mExtConn.send(data, datalen); 101 | } 102 | 103 | virtual void onError(Connection *pConn) 104 | { 105 | WarningPrint("occur an error at an internal connection! reason:%s", coreStrError()); 106 | _reconnectInternal(); 107 | } 108 | 109 | // FastConnection::Handler 110 | virtual void onDisconnected(FastConnection *pConn) 111 | { 112 | if (mpHandler) 113 | mpHandler->onExtConnDisconnected(this); 114 | } 115 | virtual void onError(FastConnection *pConn) 116 | { 117 | if (mpHandler) 118 | mpHandler->onExtConnError(this); 119 | } 120 | 121 | virtual void onCreateKcpTunnelFailed(FastConnection *pConn) 122 | { 123 | if (mpHandler) 124 | mpHandler->onExtConnError(this); 125 | } 126 | 127 | virtual void onRecv(FastConnection *pConn, const void *data, size_t datalen) 128 | { 129 | if (!mIntConn.isConnected()) 130 | { 131 | _reconnectInternal(); 132 | mCache->cache(data, datalen); 133 | } 134 | else 135 | { 136 | _flushAll(); 137 | mIntConn.send(data, datalen); 138 | } 139 | } 140 | 141 | // TimerHandler 142 | virtual void onTimeout(TimerHandle handle, void *pUser) 143 | { 144 | if (handle == mHeartBeatTimer) 145 | { 146 | mExtConn.triggerHeartBeatPacket(); 147 | } 148 | else if (handle == mConnCheckTimer) 149 | { 150 | const HeartBeatRecord &rec = mExtConn.getHeartBeatRecord(); 151 | 152 | if (rec.isTimeout()) 153 | { 154 | InfoPrint("External Connection Timeout!"); 155 | if (mpHandler) 156 | mpHandler->onExtConnError(this); 157 | } 158 | } 159 | } 160 | 161 | void _reconnectInternal() 162 | { 163 | ulong curtick = core::getClock(); 164 | if (curtick > mLastExtConnTime+1000) 165 | { 166 | mLastExtConnTime = curtick; 167 | mIntConn.connect((const SA *)&ConnectAddr, sizeof(ConnectAddr)); 168 | } 169 | } 170 | 171 | void _flushAll() 172 | { 173 | if (mIntConn.isConnected()) 174 | { 175 | mCache->flushAll(); 176 | } 177 | } 178 | bool flush(const void *data, size_t len) 179 | { 180 | mIntConn.send(data, len); 181 | return true; 182 | } 183 | 184 | private: 185 | typedef Cache MyCache; 186 | 187 | EventPoller *mEventPoller; 188 | Handler *mpHandler; 189 | 190 | Connection mIntConn; 191 | FastConnection mExtConn; 192 | 193 | MyCache *mCache; 194 | 195 | ulong mLastExtConnTime; 196 | 197 | TimerHandle mHeartBeatTimer; 198 | TimerHandle mConnCheckTimer; 199 | }; 200 | //-------------------------------------------------------------------------- 201 | 202 | //-------------------------------------------------------------------------- 203 | class Server : public Listener::Handler, public ServerBridge::Handler 204 | { 205 | public: 206 | Server(EventPoller *poller) 207 | :Listener::Handler() 208 | ,mEventPoller(poller) 209 | ,mListener(poller) 210 | ,mBridges() 211 | ,mShutedBridges() 212 | { 213 | } 214 | 215 | virtual ~Server() 216 | { 217 | } 218 | 219 | bool create(const SA *sa, socklen_t salen) 220 | { 221 | if (!mListener.initialise(sa, salen)) 222 | { 223 | ErrorPrint("create listener failed."); 224 | return false; 225 | } 226 | mListener.setEventHandler(this); 227 | 228 | return true; 229 | } 230 | 231 | void finalise() 232 | { 233 | mListener.finalise(); 234 | 235 | update(); 236 | BridgeList::iterator it = mBridges.begin(); 237 | for (; it != mBridges.end(); ++it) 238 | { 239 | ServerBridge *bridge = *it; 240 | if (bridge) 241 | { 242 | bridge->shutdown(); 243 | delete bridge; 244 | } 245 | } 246 | mBridges.clear(); 247 | } 248 | 249 | // call it ervery frame 250 | void update() 251 | { 252 | BridgeList::iterator it = mShutedBridges.begin(); 253 | for (; it != mShutedBridges.end(); ++it) 254 | { 255 | (*it)->shutdown(); 256 | delete *it; 257 | } 258 | mShutedBridges.clear(); 259 | } 260 | 261 | virtual void onAccept(int connfd) 262 | { 263 | ServerBridge *bridge = new ServerBridge(mEventPoller, this); 264 | if (!bridge->acceptConnection(connfd)) 265 | { 266 | delete bridge; 267 | return; 268 | } 269 | 270 | mBridges.insert(bridge); 271 | DebugPrint("a fast connection createted! cursize:%u", mBridges.size()); 272 | } 273 | 274 | virtual void onExtConnDisconnected(ServerBridge *pBridge) 275 | { 276 | onBridgeShut(pBridge); 277 | DebugPrint("a fast connection closed! cursize:%u", mBridges.size()); 278 | } 279 | 280 | virtual void onExtConnError(ServerBridge *pBridge) 281 | { 282 | onBridgeShut(pBridge); 283 | InfoPrint("a fast connection occur error! cursize:%u, reason:%s", mBridges.size(), coreStrError()); 284 | } 285 | 286 | private: 287 | void onBridgeShut(ServerBridge *pBridge) 288 | { 289 | BridgeList::iterator it = mBridges.find(pBridge); 290 | if (it != mBridges.end()) 291 | { 292 | mBridges.erase(it); 293 | } 294 | 295 | mShutedBridges.insert(pBridge); 296 | } 297 | 298 | private: 299 | typedef std::set BridgeList; 300 | 301 | EventPoller *mEventPoller; 302 | Listener mListener; 303 | 304 | BridgeList mBridges; 305 | BridgeList mShutedBridges; 306 | }; 307 | //-------------------------------------------------------------------------- 308 | 309 | static bool s_continueMainLoop = true; 310 | void sigHandler(int signo) 311 | { 312 | switch (signo) 313 | { 314 | case SIGPIPE: 315 | { 316 | WarningPrint("broken pipe!"); 317 | } 318 | break; 319 | case SIGINT: 320 | { 321 | InfoPrint("catch SIGINT!"); 322 | s_continueMainLoop = false; 323 | } 324 | break; 325 | case SIGQUIT: 326 | { 327 | InfoPrint("catch SIGQUIT!"); 328 | s_continueMainLoop = false; 329 | } 330 | break; 331 | case SIGKILL: 332 | { 333 | InfoPrint("catch SIGKILL!"); 334 | s_continueMainLoop = false; 335 | } 336 | break; 337 | case SIGTERM: 338 | { 339 | InfoPrint("catch SIGTERM!"); 340 | s_continueMainLoop = false; 341 | } 342 | break; 343 | default: 344 | break; 345 | } 346 | } 347 | 348 | int main(int argc, char *argv[]) 349 | { 350 | // parse parameter 351 | int pidFlags = 0; 352 | bool bVerbose = false; 353 | const char *confPath = NULL; 354 | const char *listenAddr = NULL; 355 | const char *kcpListenAddr = NULL; 356 | const char *connectAddr = NULL; 357 | const char *pidPath = NULL; 358 | 359 | int opt = 0; 360 | while ((opt = getopt(argc, argv, "f:c:l:r:v")) != -1) 361 | { 362 | switch (opt) 363 | { 364 | case 'c': 365 | confPath = optarg; 366 | break; 367 | case 'l': 368 | listenAddr = optarg; 369 | break; 370 | case 'u': 371 | kcpListenAddr = optarg; 372 | break; 373 | case 'r': 374 | connectAddr = optarg; 375 | break; 376 | case 'f': 377 | pidFlags = 1; 378 | pidPath = optarg; 379 | break; 380 | case 'v': 381 | bVerbose = true; 382 | break; 383 | default: 384 | break; 385 | } 386 | } 387 | 388 | // daemoniize 389 | int logLevel = InfoLog | WarningLog | ErrorLog | EmphasisLog; 390 | if (bVerbose) 391 | logLevel |= DebugLog; 392 | 393 | if (pidFlags) 394 | { 395 | daemonize(pidPath); 396 | 397 | if (log_initialise(logLevel) != 0) 398 | { 399 | fprintf(stderr, "init log failed!"); 400 | exit(1); 401 | } 402 | 403 | log_reg_filelog("log", "tunsvr-", "/var/log", "tunsvr-old-", "/var/log"); 404 | } 405 | else 406 | { 407 | if (log_initialise(logLevel) != 0) 408 | { 409 | fprintf(stderr, "init log failed!"); 410 | exit(1); 411 | } 412 | 413 | log_reg_filelog("log", "tunsvr-", "/tmp", "tunsvr-old-", "/tmp"); 414 | log_reg_console(); 415 | } 416 | 417 | if (argc == 1) 418 | { 419 | confPath = DEFAULT_CONF_PATH; 420 | } 421 | if (confPath) 422 | { 423 | Ini ini(confPath); 424 | static std::string s_listenAddr = ini.getString("server", "listen", ""); 425 | static std::string s_kcpListenAddr = ini.getString("server", "kcplisten", s_listenAddr.c_str()); 426 | static std::string s_connectAddr = ini.getString("server", "connect", ""); 427 | if (s_listenAddr != "") 428 | listenAddr = s_listenAddr.c_str(); 429 | if (s_connectAddr != "") 430 | connectAddr = s_connectAddr.c_str(); 431 | if (s_kcpListenAddr != "") 432 | kcpListenAddr = s_kcpListenAddr.c_str(); 433 | } 434 | 435 | if (NULL == listenAddr || NULL == connectAddr || NULL == kcpListenAddr) 436 | { 437 | fprintf(stderr, "no argument assigned or parse argument failed!\n"); 438 | log_finalise(); 439 | exit(EXIT_FAILURE); 440 | } 441 | if (!core::str2Ipv4(listenAddr, ListenAddr) || 442 | !core::str2Ipv4(connectAddr, ConnectAddr) || 443 | !core::str2Ipv4(kcpListenAddr, KcpListenAddr)) 444 | { 445 | ErrorPrint("invalid socket address!"); 446 | log_finalise(); 447 | exit(EXIT_FAILURE); 448 | } 449 | 450 | // create event poller 451 | #ifdef HAS_EPOLL 452 | EventPoller *netPoller = new EpollPoller(); 453 | #else 454 | EventPoller *netPoller = new SelectPoller(); 455 | #endif 456 | 457 | // kcp tunnel manager 458 | gTunnelManager = new MyTunnelGroup(netPoller); 459 | if (!gTunnelManager->create((const SA *)&KcpListenAddr, sizeof(KcpListenAddr))) 460 | { 461 | ErrorPrint("initialise Tunnel Manager error!"); 462 | delete netPoller; 463 | log_finalise(); 464 | exit(EXIT_FAILURE); 465 | } 466 | 467 | // create server 468 | Server svr(netPoller); 469 | if (!svr.create((const SA *)&ListenAddr, sizeof(ListenAddr))) 470 | { 471 | ErrorPrint("create server error!"); 472 | gTunnelManager->shutdown(); 473 | delete gTunnelManager; 474 | delete netPoller; 475 | log_finalise(); 476 | exit(EXIT_FAILURE); 477 | } 478 | 479 | struct sigaction newAct; 480 | newAct.sa_handler = sigHandler; 481 | sigemptyset(&newAct.sa_mask); 482 | newAct.sa_flags = 0; 483 | 484 | sigaction(SIGPIPE, &newAct, NULL); 485 | 486 | sigaction(SIGINT, &newAct, NULL); 487 | sigaction(SIGQUIT, &newAct, NULL); 488 | 489 | // sigaction(SIGKILL, &newAct, NULL); 490 | sigaction(SIGTERM, &newAct, NULL); 491 | 492 | static const uint32 MAX_WAIT = 60000; 493 | double maxWait = 0; 494 | uint32 curClock = 0, nextKcpUpdateInterval = 0, nextTimerCheckInterval = 0; 495 | DebugPrint("Enter Main Loop..."); 496 | while (s_continueMainLoop) 497 | { 498 | curClock = core::getClock(); 499 | 500 | netPoller->processPendingEvents(maxWait); 501 | 502 | nextKcpUpdateInterval = gTunnelManager->update(); 503 | 504 | gTimer.process(curClock); 505 | nextTimerCheckInterval = gTimer.nextExp(curClock); 506 | if (0 == nextTimerCheckInterval) 507 | nextTimerCheckInterval = MAX_WAIT; 508 | 509 | svr.update(); 510 | 511 | maxWait = min(nextKcpUpdateInterval, nextTimerCheckInterval); 512 | maxWait *= 0.001f; 513 | } 514 | DebugPrint("Leave Main Loop..."); 515 | 516 | // finalise 517 | svr.finalise(); 518 | 519 | gTunnelManager->shutdown(); 520 | delete gTunnelManager; 521 | 522 | delete netPoller; 523 | 524 | // uninit log 525 | DebugPrint("Exit Fasttun!"); 526 | log_finalise(); 527 | exit(0); 528 | } 529 | -------------------------------------------------------------------------------- /kcp/ikcp.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #include "ikcp.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | 21 | //===================================================================== 22 | // KCP BASIC 23 | //===================================================================== 24 | const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto 25 | const IUINT32 IKCP_RTO_MIN = 100; // normal min rto 26 | const IUINT32 IKCP_RTO_DEF = 200; 27 | const IUINT32 IKCP_RTO_MAX = 60000; 28 | const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data 29 | const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack 30 | const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) 31 | const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) 32 | const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK 33 | const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS 34 | const IUINT32 IKCP_WND_SND = 32; 35 | const IUINT32 IKCP_WND_RCV = 32; 36 | const IUINT32 IKCP_MTU_DEF = 1400; 37 | const IUINT32 IKCP_ACK_FAST = 3; 38 | const IUINT32 IKCP_INTERVAL = 100; 39 | const IUINT32 IKCP_OVERHEAD = 24; 40 | const IUINT32 IKCP_DEADLINK = 10; 41 | const IUINT32 IKCP_THRESH_INIT = 2; 42 | const IUINT32 IKCP_THRESH_MIN = 2; 43 | const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size 44 | const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window 45 | 46 | 47 | //--------------------------------------------------------------------- 48 | // encode / decode 49 | //--------------------------------------------------------------------- 50 | 51 | /* encode 8 bits unsigned int */ 52 | static inline char *ikcp_encode8u(char *p, unsigned char c) 53 | { 54 | *(unsigned char*)p++ = c; 55 | return p; 56 | } 57 | 58 | /* decode 8 bits unsigned int */ 59 | static inline const char *ikcp_decode8u(const char *p, unsigned char *c) 60 | { 61 | *c = *(unsigned char*)p++; 62 | return p; 63 | } 64 | 65 | /* encode 16 bits unsigned int (lsb) */ 66 | static inline char *ikcp_encode16u(char *p, unsigned short w) 67 | { 68 | #if IWORDS_BIG_ENDIAN 69 | *(unsigned char*)(p + 0) = (w & 255); 70 | *(unsigned char*)(p + 1) = (w >> 8); 71 | #else 72 | *(unsigned short*)(p) = w; 73 | #endif 74 | p += 2; 75 | return p; 76 | } 77 | 78 | /* decode 16 bits unsigned int (lsb) */ 79 | static inline const char *ikcp_decode16u(const char *p, unsigned short *w) 80 | { 81 | #if IWORDS_BIG_ENDIAN 82 | *w = *(const unsigned char*)(p + 1); 83 | *w = *(const unsigned char*)(p + 0) + (*w << 8); 84 | #else 85 | *w = *(const unsigned short*)p; 86 | #endif 87 | p += 2; 88 | return p; 89 | } 90 | 91 | /* encode 32 bits unsigned int (lsb) */ 92 | static inline char *ikcp_encode32u(char *p, IUINT32 l) 93 | { 94 | #if IWORDS_BIG_ENDIAN 95 | *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); 96 | *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); 97 | *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); 98 | *(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff); 99 | #else 100 | *(IUINT32*)p = l; 101 | #endif 102 | p += 4; 103 | return p; 104 | } 105 | 106 | /* decode 32 bits unsigned int (lsb) */ 107 | static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) 108 | { 109 | #if IWORDS_BIG_ENDIAN 110 | *l = *(const unsigned char*)(p + 3); 111 | *l = *(const unsigned char*)(p + 2) + (*l << 8); 112 | *l = *(const unsigned char*)(p + 1) + (*l << 8); 113 | *l = *(const unsigned char*)(p + 0) + (*l << 8); 114 | #else 115 | *l = *(const IUINT32*)p; 116 | #endif 117 | p += 4; 118 | return p; 119 | } 120 | 121 | static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) { 122 | return a <= b ? a : b; 123 | } 124 | 125 | static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) { 126 | return a >= b ? a : b; 127 | } 128 | 129 | static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper) 130 | { 131 | return _imin_(_imax_(lower, middle), upper); 132 | } 133 | 134 | static inline long _itimediff(IUINT32 later, IUINT32 earlier) 135 | { 136 | return ((IINT32)(later - earlier)); 137 | } 138 | 139 | //--------------------------------------------------------------------- 140 | // manage segment 141 | //--------------------------------------------------------------------- 142 | typedef struct IKCPSEG IKCPSEG; 143 | 144 | static void* (*ikcp_malloc_hook)(size_t) = NULL; 145 | static void (*ikcp_free_hook)(void *) = NULL; 146 | 147 | // internal malloc 148 | static void* ikcp_malloc(size_t size) { 149 | if (ikcp_malloc_hook) 150 | return ikcp_malloc_hook(size); 151 | return malloc(size); 152 | } 153 | 154 | // internal free 155 | static void ikcp_free(void *ptr) { 156 | if (ikcp_free_hook) { 157 | ikcp_free_hook(ptr); 158 | } else { 159 | free(ptr); 160 | } 161 | } 162 | 163 | // redefine allocator 164 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) 165 | { 166 | ikcp_malloc_hook = new_malloc; 167 | ikcp_free_hook = new_free; 168 | } 169 | 170 | // allocate a new kcp segment 171 | static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size) 172 | { 173 | return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); 174 | } 175 | 176 | // delete a segment 177 | static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg) 178 | { 179 | ikcp_free(seg); 180 | } 181 | 182 | // write log 183 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...) 184 | { 185 | char buffer[1024]; 186 | va_list argptr; 187 | if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return; 188 | va_start(argptr, fmt); 189 | vsprintf(buffer, fmt, argptr); 190 | va_end(argptr); 191 | kcp->writelog(buffer, kcp, kcp->user); 192 | } 193 | 194 | // check log mask 195 | static int ikcp_canlog(const ikcpcb *kcp, int mask) 196 | { 197 | if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0; 198 | return 1; 199 | } 200 | 201 | // output segment 202 | static int ikcp_output(ikcpcb *kcp, const void *data, int size) 203 | { 204 | assert(kcp); 205 | assert(kcp->output); 206 | if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) { 207 | ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size); 208 | } 209 | if (size == 0) return 0; 210 | return kcp->output((const char*)data, size, kcp, kcp->user); 211 | } 212 | 213 | // output queue 214 | void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head) 215 | { 216 | #if 0 217 | const struct IQUEUEHEAD *p; 218 | printf("<%s>: [", name); 219 | for (p = head->next; p != head; p = p->next) { 220 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 221 | printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000)); 222 | if (p->next != head) printf(","); 223 | } 224 | printf("]\n"); 225 | #endif 226 | } 227 | 228 | 229 | //--------------------------------------------------------------------- 230 | // create a new kcpcb 231 | //--------------------------------------------------------------------- 232 | ikcpcb* ikcp_create(IUINT32 conv, void *user) 233 | { 234 | ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB)); 235 | if (kcp == NULL) return NULL; 236 | kcp->conv = conv; 237 | kcp->user = user; 238 | kcp->snd_una = 0; 239 | kcp->snd_nxt = 0; 240 | kcp->rcv_nxt = 0; 241 | kcp->ts_recent = 0; 242 | kcp->ts_lastack = 0; 243 | kcp->ts_probe = 0; 244 | kcp->probe_wait = 0; 245 | kcp->snd_wnd = IKCP_WND_SND; 246 | kcp->rcv_wnd = IKCP_WND_RCV; 247 | kcp->rmt_wnd = IKCP_WND_RCV; 248 | kcp->cwnd = 0; 249 | kcp->incr = 0; 250 | kcp->probe = 0; 251 | kcp->mtu = IKCP_MTU_DEF; 252 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 253 | 254 | kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3); 255 | if (kcp->buffer == NULL) { 256 | ikcp_free(kcp); 257 | return NULL; 258 | } 259 | 260 | iqueue_init(&kcp->snd_queue); 261 | iqueue_init(&kcp->rcv_queue); 262 | iqueue_init(&kcp->snd_buf); 263 | iqueue_init(&kcp->rcv_buf); 264 | kcp->nrcv_buf = 0; 265 | kcp->nsnd_buf = 0; 266 | kcp->nrcv_que = 0; 267 | kcp->nsnd_que = 0; 268 | kcp->state = 0; 269 | kcp->acklist = NULL; 270 | kcp->ackblock = 0; 271 | kcp->ackcount = 0; 272 | kcp->rx_srtt = 0; 273 | kcp->rx_rttval = 0; 274 | kcp->rx_rto = IKCP_RTO_DEF; 275 | kcp->rx_minrto = IKCP_RTO_MIN; 276 | kcp->current = 0; 277 | kcp->interval = IKCP_INTERVAL; 278 | kcp->ts_flush = IKCP_INTERVAL; 279 | kcp->nodelay = 0; 280 | kcp->updated = 0; 281 | kcp->logmask = 0; 282 | kcp->ssthresh = IKCP_THRESH_INIT; 283 | kcp->fastresend = 0; 284 | kcp->nocwnd = 0; 285 | kcp->xmit = 0; 286 | kcp->dead_link = IKCP_DEADLINK; 287 | kcp->output = NULL; 288 | kcp->writelog = NULL; 289 | 290 | return kcp; 291 | } 292 | 293 | 294 | //--------------------------------------------------------------------- 295 | // release a new kcpcb 296 | //--------------------------------------------------------------------- 297 | void ikcp_release(ikcpcb *kcp) 298 | { 299 | assert(kcp); 300 | if (kcp) { 301 | IKCPSEG *seg; 302 | while (!iqueue_is_empty(&kcp->snd_buf)) { 303 | seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node); 304 | iqueue_del(&seg->node); 305 | ikcp_segment_delete(kcp, seg); 306 | } 307 | while (!iqueue_is_empty(&kcp->rcv_buf)) { 308 | seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 309 | iqueue_del(&seg->node); 310 | ikcp_segment_delete(kcp, seg); 311 | } 312 | while (!iqueue_is_empty(&kcp->snd_queue)) { 313 | seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); 314 | iqueue_del(&seg->node); 315 | ikcp_segment_delete(kcp, seg); 316 | } 317 | while (!iqueue_is_empty(&kcp->rcv_queue)) { 318 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 319 | iqueue_del(&seg->node); 320 | ikcp_segment_delete(kcp, seg); 321 | } 322 | if (kcp->buffer) { 323 | ikcp_free(kcp->buffer); 324 | } 325 | if (kcp->acklist) { 326 | ikcp_free(kcp->acklist); 327 | } 328 | 329 | kcp->nrcv_buf = 0; 330 | kcp->nsnd_buf = 0; 331 | kcp->nrcv_que = 0; 332 | kcp->nsnd_que = 0; 333 | kcp->ackcount = 0; 334 | kcp->buffer = NULL; 335 | kcp->acklist = NULL; 336 | ikcp_free(kcp); 337 | } 338 | } 339 | 340 | 341 | 342 | //--------------------------------------------------------------------- 343 | // user/upper level recv: returns size, returns below zero for EAGAIN 344 | //--------------------------------------------------------------------- 345 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len) 346 | { 347 | struct IQUEUEHEAD *p; 348 | int ispeek = (len < 0)? 1 : 0; 349 | int peeksize; 350 | int recover = 0; 351 | IKCPSEG *seg; 352 | assert(kcp); 353 | 354 | if (iqueue_is_empty(&kcp->rcv_queue)) 355 | return -1; 356 | 357 | if (len < 0) len = -len; 358 | 359 | peeksize = ikcp_peeksize(kcp); 360 | 361 | if (peeksize < 0) 362 | return -2; 363 | 364 | if (peeksize > len) 365 | return -3; 366 | 367 | if (kcp->nrcv_que >= kcp->rcv_wnd) 368 | recover = 1; 369 | 370 | // merge fragment 371 | for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) { 372 | int fragment; 373 | seg = iqueue_entry(p, IKCPSEG, node); 374 | p = p->next; 375 | 376 | if (buffer) { 377 | memcpy(buffer, seg->data, seg->len); 378 | buffer += seg->len; 379 | } 380 | 381 | len += seg->len; 382 | fragment = seg->frg; 383 | 384 | if (ikcp_canlog(kcp, IKCP_LOG_RECV)) { 385 | ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", seg->sn); 386 | } 387 | 388 | if (ispeek == 0) { 389 | iqueue_del(&seg->node); 390 | ikcp_segment_delete(kcp, seg); 391 | kcp->nrcv_que--; 392 | } 393 | 394 | if (fragment == 0) 395 | break; 396 | } 397 | 398 | assert(len == peeksize); 399 | 400 | // move available data from rcv_buf -> rcv_queue 401 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 402 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 403 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 404 | iqueue_del(&seg->node); 405 | kcp->nrcv_buf--; 406 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 407 | kcp->nrcv_que++; 408 | kcp->rcv_nxt++; 409 | } else { 410 | break; 411 | } 412 | } 413 | 414 | // fast recover 415 | if (kcp->nrcv_que < kcp->rcv_wnd && recover) { 416 | // ready to send back IKCP_CMD_WINS in ikcp_flush 417 | // tell remote my window size 418 | kcp->probe |= IKCP_ASK_TELL; 419 | } 420 | 421 | return len; 422 | } 423 | 424 | 425 | //--------------------------------------------------------------------- 426 | // peek data size 427 | //--------------------------------------------------------------------- 428 | int ikcp_peeksize(const ikcpcb *kcp) 429 | { 430 | struct IQUEUEHEAD *p; 431 | IKCPSEG *seg; 432 | int length = 0; 433 | 434 | assert(kcp); 435 | 436 | if (iqueue_is_empty(&kcp->rcv_queue)) return -1; 437 | 438 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 439 | if (seg->frg == 0) return seg->len; 440 | 441 | if (kcp->nrcv_que < seg->frg + 1) return -1; 442 | 443 | for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) { 444 | seg = iqueue_entry(p, IKCPSEG, node); 445 | length += seg->len; 446 | if (seg->frg == 0) break; 447 | } 448 | 449 | return length; 450 | } 451 | 452 | 453 | //--------------------------------------------------------------------- 454 | // user/upper level send, returns below zero for error 455 | //--------------------------------------------------------------------- 456 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len) 457 | { 458 | IKCPSEG *seg; 459 | int count, i; 460 | 461 | assert(kcp->mss > 0); 462 | if (len < 0) return -1; 463 | 464 | if (len <= (int)kcp->mss) count = 1; 465 | else count = (len + kcp->mss - 1) / kcp->mss; 466 | 467 | if (count > 255) return -2; 468 | 469 | if (count == 0) count = 1; 470 | 471 | // fragment 472 | for (i = 0; i < count; i++) { 473 | int size = len > (int)kcp->mss ? (int)kcp->mss : len; 474 | seg = ikcp_segment_new(kcp, size); 475 | assert(seg); 476 | if (seg == NULL) { 477 | return -2; 478 | } 479 | if (buffer && len > 0) { 480 | memcpy(seg->data, buffer, size); 481 | } 482 | seg->len = size; 483 | seg->frg = count - i - 1; 484 | iqueue_init(&seg->node); 485 | iqueue_add_tail(&seg->node, &kcp->snd_queue); 486 | kcp->nsnd_que++; 487 | if (buffer) { 488 | buffer += size; 489 | } 490 | len -= size; 491 | } 492 | 493 | return 0; 494 | } 495 | 496 | 497 | //--------------------------------------------------------------------- 498 | // parse ack 499 | //--------------------------------------------------------------------- 500 | static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) 501 | { 502 | IINT32 rto = 0; 503 | if (kcp->rx_srtt == 0) { 504 | kcp->rx_srtt = rtt; 505 | kcp->rx_rttval = rtt / 2; 506 | } else { 507 | long delta = rtt - kcp->rx_srtt; 508 | if (delta < 0) delta = -delta; 509 | kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; 510 | kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; 511 | if (kcp->rx_srtt < 1) kcp->rx_srtt = 1; 512 | } 513 | rto = kcp->rx_srtt + _imax_(1, 4 * kcp->rx_rttval); 514 | kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX); 515 | } 516 | 517 | static void ikcp_shrink_buf(ikcpcb *kcp) 518 | { 519 | struct IQUEUEHEAD *p = kcp->snd_buf.next; 520 | if (p != &kcp->snd_buf) { 521 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 522 | kcp->snd_una = seg->sn; 523 | } else { 524 | kcp->snd_una = kcp->snd_nxt; 525 | } 526 | } 527 | 528 | static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn) 529 | { 530 | struct IQUEUEHEAD *p, *next; 531 | 532 | if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) 533 | return; 534 | 535 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 536 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 537 | next = p->next; 538 | if (sn == seg->sn) { 539 | iqueue_del(p); 540 | ikcp_segment_delete(kcp, seg); 541 | kcp->nsnd_buf--; 542 | break; 543 | } 544 | else { 545 | seg->fastack++; 546 | } 547 | } 548 | } 549 | 550 | static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) 551 | { 552 | #if 1 553 | struct IQUEUEHEAD *p, *next; 554 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 555 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 556 | next = p->next; 557 | if (_itimediff(una, seg->sn) > 0) { 558 | iqueue_del(p); 559 | ikcp_segment_delete(kcp, seg); 560 | kcp->nsnd_buf--; 561 | } else { 562 | break; 563 | } 564 | } 565 | #endif 566 | } 567 | 568 | 569 | //--------------------------------------------------------------------- 570 | // ack append 571 | //--------------------------------------------------------------------- 572 | static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) 573 | { 574 | size_t newsize = kcp->ackcount + 1; 575 | IUINT32 *ptr; 576 | 577 | if (newsize > kcp->ackblock) { 578 | IUINT32 *acklist; 579 | size_t newblock; 580 | 581 | for (newblock = 8; newblock < newsize; newblock <<= 1); 582 | acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2); 583 | 584 | if (acklist == NULL) { 585 | assert(acklist != NULL); 586 | abort(); 587 | } 588 | 589 | if (kcp->acklist != NULL) { 590 | size_t x; 591 | for (x = 0; x < kcp->ackcount; x++) { 592 | acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0]; 593 | acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; 594 | } 595 | ikcp_free(kcp->acklist); 596 | } 597 | 598 | kcp->acklist = acklist; 599 | kcp->ackblock = newblock; 600 | } 601 | 602 | ptr = &kcp->acklist[kcp->ackcount * 2]; 603 | ptr[0] = sn; 604 | ptr[1] = ts; 605 | kcp->ackcount++; 606 | } 607 | 608 | static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts) 609 | { 610 | if (sn) sn[0] = kcp->acklist[p * 2 + 0]; 611 | if (ts) ts[0] = kcp->acklist[p * 2 + 1]; 612 | } 613 | 614 | 615 | //--------------------------------------------------------------------- 616 | // parse data 617 | //--------------------------------------------------------------------- 618 | void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) 619 | { 620 | struct IQUEUEHEAD *p, *prev; 621 | IUINT32 sn = newseg->sn; 622 | int repeat = 0; 623 | 624 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || 625 | _itimediff(sn, kcp->rcv_nxt) < 0) { 626 | ikcp_segment_delete(kcp, newseg); 627 | return; 628 | } 629 | 630 | for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) { 631 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 632 | prev = p->prev; 633 | if (seg->sn == sn) { 634 | repeat = 1; 635 | break; 636 | } 637 | if (_itimediff(sn, seg->sn) > 0) { 638 | break; 639 | } 640 | } 641 | 642 | if (repeat == 0) { 643 | iqueue_init(&newseg->node); 644 | iqueue_add(&newseg->node, p); 645 | kcp->nrcv_buf++; 646 | } else { 647 | ikcp_segment_delete(kcp, newseg); 648 | } 649 | 650 | #if 0 651 | ikcp_qprint("rcvbuf", &kcp->rcv_buf); 652 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 653 | #endif 654 | 655 | // move available data from rcv_buf -> rcv_queue 656 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 657 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 658 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 659 | iqueue_del(&seg->node); 660 | kcp->nrcv_buf--; 661 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 662 | kcp->nrcv_que++; 663 | kcp->rcv_nxt++; 664 | } else { 665 | break; 666 | } 667 | } 668 | 669 | #if 0 670 | ikcp_qprint("queue", &kcp->rcv_queue); 671 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 672 | #endif 673 | 674 | #if 1 675 | // printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que); 676 | // printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que); 677 | #endif 678 | } 679 | 680 | // get conv from packet 681 | // return 1 if get conv success. 682 | // return 0 if get conv error. 683 | int ikcp_get_conv(const char *data, long size, IUINT32* conv_out) 684 | { 685 | if (data == NULL || size < (int)IKCP_OVERHEAD) 686 | return 0; 687 | 688 | ikcp_decode32u(data, conv_out); 689 | return 1; 690 | } 691 | 692 | //--------------------------------------------------------------------- 693 | // input data 694 | //--------------------------------------------------------------------- 695 | int ikcp_input(ikcpcb *kcp, const char *data, long size) 696 | { 697 | IUINT32 una = kcp->snd_una; 698 | 699 | if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { 700 | ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", size); 701 | } 702 | 703 | if (data == NULL || size < 24) return 0; 704 | 705 | while (1) { 706 | IUINT32 ts, sn, len, una, conv; 707 | IUINT16 wnd; 708 | IUINT8 cmd, frg; 709 | IKCPSEG *seg; 710 | 711 | if (size < (int)IKCP_OVERHEAD) break; 712 | 713 | data = ikcp_decode32u(data, &conv); 714 | if (conv != kcp->conv) return -1; 715 | 716 | data = ikcp_decode8u(data, &cmd); 717 | data = ikcp_decode8u(data, &frg); 718 | data = ikcp_decode16u(data, &wnd); 719 | data = ikcp_decode32u(data, &ts); 720 | data = ikcp_decode32u(data, &sn); 721 | data = ikcp_decode32u(data, &una); 722 | data = ikcp_decode32u(data, &len); 723 | 724 | size -= IKCP_OVERHEAD; 725 | 726 | if ((long)size < (long)len) return -2; 727 | 728 | if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && 729 | cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS) 730 | return -3; 731 | 732 | kcp->rmt_wnd = wnd; 733 | ikcp_parse_una(kcp, una); 734 | ikcp_shrink_buf(kcp); 735 | 736 | if (cmd == IKCP_CMD_ACK) { 737 | if (_itimediff(kcp->current, ts) >= 0) { 738 | ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); 739 | } 740 | ikcp_parse_ack(kcp, sn); 741 | ikcp_shrink_buf(kcp); 742 | if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { 743 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 744 | "input ack: sn=%lu rtt=%ld rto=%ld", sn, 745 | (long)_itimediff(kcp->current, ts), 746 | (long)kcp->rx_rto); 747 | } 748 | } 749 | else if (cmd == IKCP_CMD_PUSH) { 750 | if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) { 751 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 752 | "input psh: sn=%lu ts=%lu", sn, ts); 753 | } 754 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) { 755 | ikcp_ack_push(kcp, sn, ts); 756 | if (_itimediff(sn, kcp->rcv_nxt) >= 0) { 757 | seg = ikcp_segment_new(kcp, len); 758 | seg->conv = conv; 759 | seg->cmd = cmd; 760 | seg->frg = frg; 761 | seg->wnd = wnd; 762 | seg->ts = ts; 763 | seg->sn = sn; 764 | seg->una = una; 765 | seg->len = len; 766 | 767 | if (len > 0) { 768 | memcpy(seg->data, data, len); 769 | } 770 | 771 | ikcp_parse_data(kcp, seg); 772 | } 773 | } 774 | } 775 | else if (cmd == IKCP_CMD_WASK) { 776 | // ready to send back IKCP_CMD_WINS in ikcp_flush 777 | // tell remote my window size 778 | kcp->probe |= IKCP_ASK_TELL; 779 | if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) { 780 | ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe"); 781 | } 782 | } 783 | else if (cmd == IKCP_CMD_WINS) { 784 | // do nothing 785 | if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) { 786 | ikcp_log(kcp, IKCP_LOG_IN_WINS, 787 | "input wins: %lu", (IUINT32)(wnd)); 788 | } 789 | } 790 | else { 791 | return -3; 792 | } 793 | 794 | data += len; 795 | size -= len; 796 | } 797 | 798 | if (_itimediff(kcp->snd_una, una) > 0) { 799 | if (kcp->cwnd < kcp->rmt_wnd) { 800 | IUINT32 mss = kcp->mss; 801 | if (kcp->cwnd < kcp->ssthresh) { 802 | kcp->cwnd++; 803 | kcp->incr += mss; 804 | } else { 805 | if (kcp->incr < mss) kcp->incr = mss; 806 | kcp->incr += (mss * mss) / kcp->incr + (mss / 16); 807 | if ((kcp->cwnd + 1) * mss <= kcp->incr) { 808 | kcp->cwnd++; 809 | } 810 | } 811 | if (kcp->cwnd > kcp->rmt_wnd) { 812 | kcp->cwnd = kcp->rmt_wnd; 813 | kcp->incr = kcp->rmt_wnd * mss; 814 | } 815 | } 816 | } 817 | 818 | return 0; 819 | } 820 | 821 | 822 | //--------------------------------------------------------------------- 823 | // ikcp_encode_seg 824 | //--------------------------------------------------------------------- 825 | static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg) 826 | { 827 | ptr = ikcp_encode32u(ptr, seg->conv); 828 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd); 829 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg); 830 | ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd); 831 | ptr = ikcp_encode32u(ptr, seg->ts); 832 | ptr = ikcp_encode32u(ptr, seg->sn); 833 | ptr = ikcp_encode32u(ptr, seg->una); 834 | ptr = ikcp_encode32u(ptr, seg->len); 835 | return ptr; 836 | } 837 | 838 | static int ikcp_wnd_unused(const ikcpcb *kcp) 839 | { 840 | if (kcp->nrcv_que < kcp->rcv_wnd) { 841 | return kcp->rcv_wnd - kcp->nrcv_que; 842 | } 843 | return 0; 844 | } 845 | 846 | 847 | //--------------------------------------------------------------------- 848 | // ikcp_flush 849 | //--------------------------------------------------------------------- 850 | void ikcp_flush(ikcpcb *kcp) 851 | { 852 | IUINT32 current = kcp->current; 853 | char *buffer = kcp->buffer; 854 | char *ptr = buffer; 855 | int count, size, i; 856 | IUINT32 resent, cwnd; 857 | IUINT32 rtomin; 858 | struct IQUEUEHEAD *p; 859 | int change = 0; 860 | int lost = 0; 861 | IKCPSEG seg; 862 | 863 | // 'ikcp_update' haven't been called. 864 | if (kcp->updated == 0) return; 865 | 866 | seg.conv = kcp->conv; 867 | seg.cmd = IKCP_CMD_ACK; 868 | seg.frg = 0; 869 | seg.wnd = ikcp_wnd_unused(kcp); 870 | seg.una = kcp->rcv_nxt; 871 | seg.len = 0; 872 | seg.sn = 0; 873 | seg.ts = 0; 874 | 875 | // flush acknowledges 876 | count = kcp->ackcount; 877 | for (i = 0; i < count; i++) { 878 | size = (int)(ptr - buffer); 879 | if (size + IKCP_OVERHEAD > (int)kcp->mtu) { 880 | ikcp_output(kcp, buffer, size); 881 | ptr = buffer; 882 | } 883 | ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); 884 | ptr = ikcp_encode_seg(ptr, &seg); 885 | } 886 | 887 | kcp->ackcount = 0; 888 | 889 | // probe window size (if remote window size equals zero) 890 | if (kcp->rmt_wnd == 0) { 891 | if (kcp->probe_wait == 0) { 892 | kcp->probe_wait = IKCP_PROBE_INIT; 893 | kcp->ts_probe = kcp->current + kcp->probe_wait; 894 | } 895 | else { 896 | if (_itimediff(kcp->current, kcp->ts_probe) >= 0) { 897 | if (kcp->probe_wait < IKCP_PROBE_INIT) 898 | kcp->probe_wait = IKCP_PROBE_INIT; 899 | kcp->probe_wait += kcp->probe_wait / 2; 900 | if (kcp->probe_wait > IKCP_PROBE_LIMIT) 901 | kcp->probe_wait = IKCP_PROBE_LIMIT; 902 | kcp->ts_probe = kcp->current + kcp->probe_wait; 903 | kcp->probe |= IKCP_ASK_SEND; 904 | } 905 | } 906 | } else { 907 | kcp->ts_probe = 0; 908 | kcp->probe_wait = 0; 909 | } 910 | 911 | // flush window probing commands 912 | if (kcp->probe & IKCP_ASK_SEND) { 913 | seg.cmd = IKCP_CMD_WASK; 914 | size = (int)(ptr - buffer); 915 | if (size + IKCP_OVERHEAD > (int)kcp->mtu) { 916 | ikcp_output(kcp, buffer, size); 917 | ptr = buffer; 918 | } 919 | ptr = ikcp_encode_seg(ptr, &seg); 920 | } 921 | 922 | // flush window probing commands 923 | if (kcp->probe & IKCP_ASK_TELL) { 924 | seg.cmd = IKCP_CMD_WINS; 925 | size = (int)(ptr - buffer); 926 | if (size + IKCP_OVERHEAD > (int)kcp->mtu) { 927 | ikcp_output(kcp, buffer, size); 928 | ptr = buffer; 929 | } 930 | ptr = ikcp_encode_seg(ptr, &seg); 931 | } 932 | 933 | kcp->probe = 0; 934 | 935 | // calculate window size 936 | cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); 937 | if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd); 938 | 939 | // move data from snd_queue to snd_buf 940 | while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) { 941 | IKCPSEG *newseg; 942 | if (iqueue_is_empty(&kcp->snd_queue)) break; 943 | 944 | newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); 945 | 946 | iqueue_del(&newseg->node); 947 | iqueue_add_tail(&newseg->node, &kcp->snd_buf); 948 | kcp->nsnd_que--; 949 | kcp->nsnd_buf++; 950 | 951 | newseg->conv = kcp->conv; 952 | newseg->cmd = IKCP_CMD_PUSH; 953 | newseg->wnd = seg.wnd; 954 | newseg->ts = current; 955 | newseg->sn = kcp->snd_nxt++; 956 | newseg->una = kcp->rcv_nxt; 957 | newseg->resendts = current; 958 | newseg->rto = kcp->rx_rto; 959 | newseg->fastack = 0; 960 | newseg->xmit = 0; 961 | } 962 | 963 | // calculate resent 964 | resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff; 965 | rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0; 966 | 967 | // flush data segments 968 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 969 | IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node); 970 | int needsend = 0; 971 | if (segment->xmit == 0) { 972 | needsend = 1; 973 | segment->xmit++; 974 | segment->rto = kcp->rx_rto; 975 | segment->resendts = current + segment->rto + rtomin; 976 | } 977 | else if (_itimediff(current, segment->resendts) >= 0) { 978 | needsend = 1; 979 | segment->xmit++; 980 | kcp->xmit++; 981 | if (kcp->nodelay == 0) { 982 | segment->rto += kcp->rx_rto; 983 | } else { 984 | segment->rto += kcp->rx_rto / 2; 985 | } 986 | segment->resendts = current + segment->rto; 987 | lost = 1; 988 | } 989 | else if (segment->fastack >= resent) { 990 | needsend = 1; 991 | segment->xmit++; 992 | segment->fastack = 0; 993 | segment->resendts = current + segment->rto; 994 | change++; 995 | } 996 | 997 | if (needsend) { 998 | int size, need; 999 | segment->ts = current; 1000 | segment->wnd = seg.wnd; 1001 | segment->una = kcp->rcv_nxt; 1002 | 1003 | size = (int)(ptr - buffer); 1004 | need = IKCP_OVERHEAD + segment->len; 1005 | 1006 | if (size + need > (int)kcp->mtu) { 1007 | ikcp_output(kcp, buffer, size); 1008 | ptr = buffer; 1009 | } 1010 | 1011 | ptr = ikcp_encode_seg(ptr, segment); 1012 | 1013 | if (segment->len > 0) { 1014 | memcpy(ptr, segment->data, segment->len); 1015 | ptr += segment->len; 1016 | } 1017 | 1018 | if (segment->xmit >= kcp->dead_link) { 1019 | kcp->state = -1; 1020 | } 1021 | } 1022 | } 1023 | 1024 | // flash remain segments 1025 | size = (int)(ptr - buffer); 1026 | if (size > 0) { 1027 | ikcp_output(kcp, buffer, size); 1028 | } 1029 | 1030 | // update ssthresh 1031 | if (change) { 1032 | IUINT32 inflight = kcp->snd_nxt - kcp->snd_una; 1033 | kcp->ssthresh = inflight / 2; 1034 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1035 | kcp->ssthresh = IKCP_THRESH_MIN; 1036 | kcp->cwnd = kcp->ssthresh + resent; 1037 | kcp->incr = kcp->cwnd * kcp->mss; 1038 | } 1039 | 1040 | if (lost) { 1041 | kcp->ssthresh = cwnd / 2; 1042 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1043 | kcp->ssthresh = IKCP_THRESH_MIN; 1044 | kcp->cwnd = 1; 1045 | kcp->incr = kcp->mss; 1046 | } 1047 | 1048 | if (kcp->cwnd < 1) { 1049 | kcp->cwnd = 1; 1050 | kcp->incr = kcp->mss; 1051 | } 1052 | } 1053 | 1054 | 1055 | //--------------------------------------------------------------------- 1056 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 1057 | // ikcp_check when to call it again (without ikcp_input/_send calling). 1058 | // 'current' - current timestamp in millisec. 1059 | //--------------------------------------------------------------------- 1060 | void ikcp_update(ikcpcb *kcp, IUINT32 current) 1061 | { 1062 | IINT32 slap; 1063 | 1064 | kcp->current = current; 1065 | 1066 | if (kcp->updated == 0) { 1067 | kcp->updated = 1; 1068 | kcp->ts_flush = kcp->current; 1069 | } 1070 | 1071 | slap = _itimediff(kcp->current, kcp->ts_flush); 1072 | 1073 | if (slap >= 10000 || slap < -10000) { 1074 | kcp->ts_flush = kcp->current; 1075 | slap = 0; 1076 | } 1077 | 1078 | if (slap >= 0) { 1079 | kcp->ts_flush += kcp->interval; 1080 | if (_itimediff(kcp->current, kcp->ts_flush) >= 0) { 1081 | kcp->ts_flush = kcp->current + kcp->interval; 1082 | } 1083 | ikcp_flush(kcp); 1084 | } 1085 | } 1086 | 1087 | 1088 | //--------------------------------------------------------------------- 1089 | // Determine when should you invoke ikcp_update: 1090 | // returns when you should invoke ikcp_update in millisec, if there 1091 | // is no ikcp_input/_send calling. you can call ikcp_update in that 1092 | // time, instead of call update repeatly. 1093 | // Important to reduce unnacessary ikcp_update invoking. use it to 1094 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 1095 | // or optimize ikcp_update when handling massive kcp connections) 1096 | //--------------------------------------------------------------------- 1097 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current) 1098 | { 1099 | IUINT32 ts_flush = kcp->ts_flush; 1100 | IINT32 tm_flush = 0x7fffffff; 1101 | IINT32 tm_packet = 0x7fffffff; 1102 | IUINT32 minimal = 0; 1103 | struct IQUEUEHEAD *p; 1104 | 1105 | if (kcp->updated == 0) { 1106 | return current; 1107 | } 1108 | 1109 | if (_itimediff(current, ts_flush) >= 10000 || 1110 | _itimediff(current, ts_flush) < -10000) { 1111 | ts_flush = current; 1112 | } 1113 | 1114 | if (_itimediff(current, ts_flush) >= 0) { 1115 | return current; 1116 | } 1117 | 1118 | tm_flush = _itimediff(ts_flush, current); 1119 | 1120 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 1121 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 1122 | IINT32 diff = _itimediff(seg->resendts, current); 1123 | if (diff <= 0) { 1124 | return current; 1125 | } 1126 | if (diff < tm_packet) tm_packet = diff; 1127 | } 1128 | 1129 | minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush); 1130 | if (minimal >= kcp->interval) minimal = kcp->interval; 1131 | 1132 | return current + minimal; 1133 | } 1134 | 1135 | 1136 | 1137 | int ikcp_setmtu(ikcpcb *kcp, int mtu) 1138 | { 1139 | char *buffer; 1140 | if (mtu < 50 || mtu < (int)IKCP_OVERHEAD) 1141 | return -1; 1142 | buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3); 1143 | if (buffer == NULL) 1144 | return -2; 1145 | kcp->mtu = mtu; 1146 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 1147 | ikcp_free(kcp->buffer); 1148 | kcp->buffer = buffer; 1149 | return 0; 1150 | } 1151 | 1152 | int ikcp_interval(ikcpcb *kcp, int interval) 1153 | { 1154 | if (interval > 5000) interval = 5000; 1155 | else if (interval < 10) interval = 10; 1156 | kcp->interval = interval; 1157 | return 0; 1158 | } 1159 | 1160 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) 1161 | { 1162 | if (nodelay >= 0) { 1163 | kcp->nodelay = nodelay; 1164 | if (nodelay) { 1165 | kcp->rx_minrto = IKCP_RTO_NDL; 1166 | } 1167 | else { 1168 | kcp->rx_minrto = IKCP_RTO_MIN; 1169 | } 1170 | } 1171 | if (interval >= 0) { 1172 | if (interval > 5000) interval = 5000; 1173 | else if (interval < 10) interval = 10; 1174 | kcp->interval = interval; 1175 | } 1176 | if (resend >= 0) { 1177 | kcp->fastresend = resend; 1178 | } 1179 | if (nc >= 0) { 1180 | kcp->nocwnd = nc; 1181 | } 1182 | return 0; 1183 | } 1184 | 1185 | 1186 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd) 1187 | { 1188 | if (kcp) { 1189 | if (sndwnd > 0) { 1190 | kcp->snd_wnd = sndwnd; 1191 | } 1192 | if (rcvwnd > 0) { 1193 | kcp->rcv_wnd = rcvwnd; 1194 | } 1195 | } 1196 | return 0; 1197 | } 1198 | 1199 | int ikcp_waitsnd(const ikcpcb *kcp) 1200 | { 1201 | return kcp->nsnd_buf + kcp->nsnd_que; 1202 | } 1203 | 1204 | 1205 | --------------------------------------------------------------------------------