├── .gitignore ├── generate ├── generate.bat ├── .gitmodules ├── Src ├── Callback.h ├── Server │ ├── EntryHandler.h │ ├── UplinkHandler.h │ ├── ServerHandler.h │ ├── EntryHandler.cpp │ ├── Main.cpp │ ├── ServerHandler.cpp │ └── UplinkHandler.cpp ├── Client │ ├── EndpointHandler.h │ ├── ClientHandler.h │ ├── DownlinkHandler.h │ ├── EndpointHandler.cpp │ ├── Main.cpp │ ├── ClientHandler.cpp │ └── DownlinkHandler.cpp └── Protocol.h ├── NOTICE ├── Marefile └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | Build/ 2 | *.sdf 3 | *.opensdf 4 | *.suo 5 | *.vcxproj.user 6 | ipch/ 7 | *.vcxproj 8 | *.vcxproj.filters 9 | *.sln -------------------------------------------------------------------------------- /generate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ ! -f "Build/Debug/mare/mare" ] && Ext/mare/compile --buildDir=Build/Debug/mare --outputDir=Build/Debug/mare --sourceDir=Ext/mare/src 4 | Build/Debug/mare/mare $@ 5 | 6 | -------------------------------------------------------------------------------- /generate.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if not exist Build\Debug\mare\mare.exe call Ext\mare\compile.bat --buildDir=Build/Debug/mare --outputDir=Build/Debug/mare --sourceDir=Ext/mare/src 4 | if not "%1"=="" (Build\Debug\mare\mare.exe %*) else Build\Debug\mare\mare.exe --vcxproj=2013 5 | 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Ext/mare"] 2 | path = Ext/mare 3 | url = https://github.com/craflin/mare.git 4 | [submodule "Ext/libnstd"] 5 | path = Ext/libnstd 6 | url = https://github.com/craflin/libnstd.git 7 | [submodule "Ext/lz4"] 8 | path = Ext/lz4 9 | url = https://github.com/Cyan4973/lz4.git 10 | -------------------------------------------------------------------------------- /Src/Callback.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Callback 7 | { 8 | public: 9 | virtual void openedClient() {} 10 | virtual void readClient() {} 11 | virtual void writeClient() {} 12 | virtual void closedClient() {} 13 | virtual void abolishedClient() {} 14 | virtual void acceptClient(Server::Handle& handle) {} 15 | virtual void executeTimer() {} 16 | }; 17 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2014 Colin Graf 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /Src/Server/EntryHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "Callback.h" 7 | 8 | class ServerHandler; 9 | 10 | class EntryHandler : public Callback 11 | { 12 | public: 13 | EntryHandler(ServerHandler& serverHandler, Server& server, uint32 connectionId); 14 | ~EntryHandler(); 15 | 16 | uint32 getConnectionId() const {return connectionId;} 17 | 18 | bool accept(Server::Handle& listenerHandle); 19 | 20 | void sendData(const byte* data, size_t size); 21 | void suspend(); 22 | void resume(); 23 | void suspendByUplink(); 24 | void resumeByUplink(); 25 | 26 | private: 27 | ServerHandler& serverHandler; 28 | Server& server; 29 | Server::Handle* handle; 30 | uint32 connectionId; 31 | uint32 addr; 32 | uint16 port; 33 | bool suspended; 34 | bool suspendedByUplink; 35 | 36 | private: // Server::Client::Listener 37 | virtual void readClient(); 38 | virtual void writeClient(); 39 | virtual void closedClient(); 40 | }; 41 | -------------------------------------------------------------------------------- /Src/Client/EndpointHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "Callback.h" 8 | 9 | class ClientHandler; 10 | 11 | class EndpointHandler : public Callback 12 | { 13 | public: 14 | EndpointHandler(ClientHandler& clientHandler, Server& server, uint32 connectionId); 15 | ~EndpointHandler(); 16 | 17 | uint32 getConnectionId() const {return connectionId;} 18 | 19 | bool connect(uint16 port); 20 | 21 | void sendData(byte* data, size_t size); 22 | void suspend(); 23 | void resume(); 24 | void suspendByDownlink(); 25 | void resumeByDownlink(); 26 | 27 | private: 28 | ClientHandler& clientHandler; 29 | Server& server; 30 | Server::Handle* handle; 31 | uint32 connectionId; 32 | uint16 port; 33 | bool connected; 34 | Buffer sendBuffer; 35 | bool suspended; 36 | bool suspendedByDownlink; 37 | 38 | private: // Callback 39 | virtual void openedClient(); 40 | virtual void abolishedClient(); 41 | virtual void closedClient(); 42 | virtual void readClient(); 43 | virtual void writeClient(); 44 | }; 45 | -------------------------------------------------------------------------------- /Src/Client/ClientHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Callback.h" 9 | 10 | #define SEND_BUFFER_SIZE (256 * 1024) 11 | #define RECV_BUFFER_SIZE (256 * 1024) 12 | 13 | class DownlinkHandler; 14 | class EndpointHandler; 15 | 16 | class ClientHandler : public Callback 17 | { 18 | public: 19 | ClientHandler(Server& server); 20 | ~ClientHandler(); 21 | 22 | const String& getSecret() const {return secret;} 23 | 24 | bool connect(uint32 addr, uint16 port, const String& secret); 25 | 26 | bool removeDownlink(); 27 | bool createEndpoint(uint32 connectionId, uint16 port); 28 | bool removeEndpoint(uint32 connectionId); 29 | bool sendDataToDownlink(uint32 connectionId, byte* data, size_t size); 30 | bool sendDataToEndpoint(uint32 connectionId, byte* data, size_t size); 31 | void sendSuspendEntry(uint32 connectionId); 32 | void sendResumeEntry(uint32 connectionId); 33 | void suspendEndpoint(uint32 connectionId); 34 | void resumeEndpoint(uint32 connectionId); 35 | void suspendAllEndpoints(); 36 | void resumeAllEndpoints(); 37 | 38 | private: 39 | Server& server; 40 | uint32 addr; 41 | uint16 port; 42 | String secret; 43 | DownlinkHandler* downlink; 44 | HashMap endpoints; 45 | bool suspendedAlldEnpoints; 46 | Server::Handle* reconnectTimer; 47 | 48 | private: // Callback 49 | virtual void executeTimer(); 50 | }; 51 | -------------------------------------------------------------------------------- /Src/Server/UplinkHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "Protocol.h" 8 | #include "Callback.h" 9 | 10 | class ServerHandler; 11 | 12 | class UplinkHandler : public Callback 13 | { 14 | public: 15 | UplinkHandler(ServerHandler& serverHandler, Server& server); 16 | ~UplinkHandler(); 17 | 18 | bool accept(Server::Handle& listenerHandle); 19 | 20 | bool sendConnect(uint32 connectionId, uint16 port); 21 | bool sendDisconnect(uint32 connectionId); 22 | bool sendData(uint32 connectionId, const byte* data, size_t size); 23 | bool sendSuspend(uint32 connectionId); 24 | bool sendResume(uint32 connectionId); 25 | 26 | private: 27 | ServerHandler& serverHandler; 28 | Server& server; 29 | Server::Handle* handle; 30 | uint32 addr; 31 | uint16 port; 32 | bool authed; 33 | Buffer lz4Buffer; 34 | Buffer readBuffer; 35 | 36 | private: 37 | void handleMessage(Protocol::MessageType messageType, byte* data, size_t size); 38 | void handleAuthMessage(Protocol::AuthMessage& authMessage); 39 | void handleDisconnectMessage(const Protocol::DisconnectMessage& disconnectMessage); 40 | void handleDataMessage(const Protocol::DataMessage& dataMessage, byte* data, size_t size); 41 | void handleSuspendMessage(const Protocol::SuspendMessage& suspendMessage); 42 | void handleResumeMessage(const Protocol::ResumeMessage& resumeMessage); 43 | 44 | private: // Callback 45 | virtual void readClient(); 46 | virtual void writeClient(); 47 | virtual void closedClient(); 48 | }; 49 | -------------------------------------------------------------------------------- /Src/Protocol.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Protocol 7 | { 8 | public: 9 | enum MessageType 10 | { 11 | error, 12 | auth, 13 | authResponse, 14 | connect, 15 | disconnect, 16 | data, 17 | suspend, 18 | resume, 19 | }; 20 | 21 | #pragma pack(push, 1) 22 | struct Header 23 | { 24 | uint32 size:24; 25 | uint8 messageType; // MessageType 26 | }; 27 | 28 | struct AuthMessage : public Header 29 | { 30 | char secret[33]; 31 | }; 32 | 33 | struct ConnectMessage : public Header 34 | { 35 | uint32 connectionId; 36 | uint16 port; 37 | }; 38 | 39 | struct DisconnectMessage : public Header 40 | { 41 | uint32 connectionId; 42 | }; 43 | 44 | struct DataMessage : public Header 45 | { 46 | uint32 connectionId; 47 | uint32 originalSize:24; 48 | }; 49 | 50 | struct SuspendMessage : public Header 51 | { 52 | uint32 connectionId; 53 | }; 54 | 55 | struct ResumeMessage : public Header 56 | { 57 | uint32 connectionId; 58 | }; 59 | #pragma pack(pop) 60 | 61 | template static void setString(char(&str)[N], const String& value) 62 | { 63 | size_t size = value.length() + 1; 64 | if(size > N - 1) 65 | size = N - 1; 66 | Memory::copy(str, (const char*)value, size); 67 | str[N - 1] = '\0'; 68 | } 69 | 70 | template static String getString(char(&str)[N]) 71 | { 72 | str[N - 1] = '\0'; 73 | String result; 74 | result.attach(str, String::length(str)); 75 | return result; 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /Src/Client/DownlinkHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "Protocol.h" 8 | #include "Callback.h" 9 | 10 | class ClientHandler; 11 | 12 | class DownlinkHandler : public Callback 13 | { 14 | public: 15 | DownlinkHandler(ClientHandler& clientHandler, Server& server); 16 | ~DownlinkHandler(); 17 | 18 | bool connect(uint32 addr, uint16 port); 19 | 20 | bool sendDisconnect(uint32 connectionId); 21 | bool sendData(uint32 connectionId, byte* data, size_t size); 22 | bool sendSuspend(uint32 connectionId); 23 | bool sendResume(uint32 connectionId); 24 | 25 | private: 26 | ClientHandler& clientHandler; 27 | Server& server; 28 | Server::Handle* handle; 29 | uint32 addr; 30 | uint16 port; 31 | bool connected; 32 | bool authed; 33 | Buffer lz4Buffer; 34 | Buffer readBuffer; 35 | 36 | private: 37 | void handleMessage(Protocol::MessageType messageType, byte* data, size_t size); 38 | void handleConnectMessage(const Protocol::ConnectMessage& connect); 39 | void handleDisconnectMessage(const Protocol::DisconnectMessage& disconnect); 40 | void handleDataMessage(const Protocol::DataMessage& message, byte* data, size_t size); 41 | void handleSuspendMessage(const Protocol::SuspendMessage& suspendMessage); 42 | void handleResumeMessage(const Protocol::ResumeMessage& resumeMessage); 43 | 44 | private: // Callback 45 | virtual void openedClient(); 46 | virtual void abolishedClient(); 47 | virtual void readClient(); 48 | virtual void writeClient(); 49 | virtual void closedClient(); 50 | }; 51 | -------------------------------------------------------------------------------- /Src/Server/ServerHandler.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Callback.h" 9 | 10 | #define SEND_BUFFER_SIZE (256 * 1024) 11 | #define RECV_BUFFER_SIZE (256 * 1024) 12 | 13 | class EntryHandler; 14 | class UplinkHandler; 15 | 16 | class ServerHandler : public Callback 17 | { 18 | public: 19 | ServerHandler(Server& server); 20 | ~ServerHandler(); 21 | 22 | const String& getSecret() const {return secret;} 23 | 24 | bool listen(uint32 addr, uint16 port, const String& secret); 25 | bool listen(uint32 addr, uint16 port, uint16 mappedPort); 26 | 27 | bool removeUplink(); 28 | bool removeEntry(uint32 connectionId); 29 | bool sendDataToEntry(uint32 connectionId, byte* data, size_t size); 30 | bool sendDataToUplink(uint32 connectionId, byte* data, size_t size); 31 | void sendSuspendEndpoint(uint32 connectionId); 32 | void sendResumeEndpoint(uint32 connectionId); 33 | void suspendEntry(uint32 connectionId); 34 | void resumeEntry(uint32 connectionId); 35 | void suspendAllEntries(); 36 | void resumeAllEntries(); 37 | 38 | private: 39 | Server& server; 40 | Server::Handle* tunnelListener; 41 | HashMap inboundListeners; 42 | String secret; 43 | UplinkHandler* uplink; 44 | HashMap entries; 45 | uint32 nextConnectionId; 46 | bool suspendedAllEntries; 47 | 48 | private: 49 | uint16 mapPort(Server::Handle& handle) {return *inboundListeners.find(&handle);} 50 | 51 | private: // Callback 52 | virtual void acceptClient(Server::Handle& handle); 53 | }; 54 | -------------------------------------------------------------------------------- /Src/Server/EntryHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "EntryHandler.h" 7 | #include "ServerHandler.h" 8 | #include "UplinkHandler.h" 9 | 10 | EntryHandler::EntryHandler(ServerHandler& serverHandler, Server& server, uint32 connectionId) 11 | : serverHandler(serverHandler), server(server), handle(0), connectionId(connectionId), suspended(false), suspendedByUplink(false) {} 12 | 13 | EntryHandler::~EntryHandler() 14 | { 15 | if(handle) 16 | { 17 | Log::infof("Closed entry connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 18 | server.close(*handle); 19 | } 20 | } 21 | 22 | bool EntryHandler::accept(Server::Handle& listenerHandle) 23 | { 24 | ASSERT(!handle); 25 | handle = server.accept(listenerHandle, this, &addr, &port); 26 | if(!handle) 27 | return false; 28 | Log::infof("Accepted entry connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 29 | return true; 30 | } 31 | 32 | void EntryHandler::sendData(const byte* data, size_t size) 33 | { 34 | size_t postponed; 35 | if(server.write(*handle, data, size, &postponed) && postponed) 36 | serverHandler.sendSuspendEndpoint(connectionId); 37 | } 38 | void EntryHandler::suspend() 39 | { 40 | suspended = true; 41 | server.suspend(*handle); 42 | } 43 | 44 | void EntryHandler::resume() 45 | { 46 | suspended = false; 47 | if(!suspendedByUplink) 48 | server.resume(*handle); 49 | } 50 | 51 | void EntryHandler::suspendByUplink() 52 | { 53 | suspendedByUplink = true; 54 | server.suspend(*handle); 55 | } 56 | 57 | void EntryHandler::resumeByUplink() 58 | { 59 | suspendedByUplink = false; 60 | if(!suspended) 61 | server.resume(*handle); 62 | } 63 | 64 | void EntryHandler::closedClient() 65 | { 66 | serverHandler.removeEntry(connectionId); 67 | } 68 | 69 | void EntryHandler::readClient() 70 | { 71 | byte buffer[RECV_BUFFER_SIZE]; 72 | size_t size; 73 | if(server.read(*handle, buffer, sizeof(buffer), size)) 74 | serverHandler.sendDataToUplink(connectionId, buffer, size); 75 | } 76 | 77 | void EntryHandler::writeClient() 78 | { 79 | serverHandler.sendResumeEndpoint(connectionId); 80 | } 81 | -------------------------------------------------------------------------------- /Marefile: -------------------------------------------------------------------------------- 1 | 2 | name = "invtun" 3 | 4 | buildDir = "Build/$(configuration)/$(target)" 5 | 6 | targets = { 7 | 8 | all = { 9 | dependencies = { "invtunc", "invtuns" } 10 | } 11 | 12 | invtunc = cppApplication + { 13 | dependencies = { "libnstd", "liblz4" } 14 | buildDir = "Build/$(configuration)/Client" 15 | output = "Build/$(configuration)/$(target)$(if $(Win32),.exe,)" 16 | includePaths = { 17 | "Ext/libnstd/include" 18 | "Ext/lz4" 19 | "Src" 20 | } 21 | libPaths = { 22 | "Build/$(configuration)/libnstd" 23 | "Build/$(configuration)/liblz4" 24 | } 25 | libs = { "nstd", "lz4" } 26 | root = { "Src/Client", "Src" } 27 | files = { 28 | "Src/Client/**.cpp" = cppSource 29 | "Src/Client/**.h" 30 | "Src/Tools/**.cpp" = cppSource 31 | "Src/Tools/**.h" 32 | "Src/Protocol.h" 33 | "Src/Callback.h" 34 | } 35 | if tool == "vcxproj" { 36 | libs += { "ws2_32" } 37 | linkFlags += { "/SUBSYSTEM:CONSOLE" } 38 | } 39 | if platform == "Linux" { 40 | libs += { "pthread", "rt" } 41 | cppFlags += { "-Wno-delete-non-virtual-dtor" } 42 | } 43 | } 44 | 45 | invtuns = cppApplication + { 46 | dependencies = { "libnstd", "liblz4" } 47 | buildDir = "Build/$(configuration)/Server" 48 | output = "Build/$(configuration)/$(target)$(if $(Win32),.exe,)" 49 | includePaths = { 50 | "Ext/libnstd/include" 51 | "Ext/lz4" 52 | "Src" 53 | } 54 | libPaths = { 55 | "Build/$(configuration)/libnstd" 56 | "Build/$(configuration)/liblz4" 57 | } 58 | libs = { "nstd", "lz4" } 59 | root = { "Src/Server", "Src" } 60 | files = { 61 | "Src/Server/**.cpp" = cppSource 62 | "Src/Server/**.h" 63 | "Src/Tools/**.cpp" = cppSource 64 | "Src/Tools/**.h" 65 | "Src/Protocol.h" 66 | "Src/Callback.h" 67 | } 68 | if tool == "vcxproj" { 69 | libs += { "ws2_32" } 70 | linkFlags += { "/SUBSYSTEM:CONSOLE" } 71 | } 72 | if platform == "Linux" { 73 | libs += { "pthread", "rt" } 74 | cppFlags += { "-Wno-delete-non-virtual-dtor" } 75 | } 76 | } 77 | 78 | include "Ext/libnstd/libnstd.mare" 79 | libnstd += { 80 | folder = "Ext" 81 | enableSocket = "true" 82 | } 83 | 84 | liblz4 = cppStaticLibrary + { 85 | folder = "Ext" 86 | includePaths = { "Ext/lz4" } 87 | root = { "Ext/lz4" } 88 | files = { 89 | "Ext/lz4/lz4.c" = cSource, 90 | "Ext/lz4/lz4.h" 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Src/Client/EndpointHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "EndpointHandler.h" 7 | #include "ClientHandler.h" 8 | 9 | EndpointHandler::EndpointHandler(ClientHandler& clientHandler, Server& server, uint32 connectionId) 10 | : clientHandler(clientHandler), server(server), handle(0), connectionId(connectionId), connected(false), suspended(false), suspendedByDownlink(false) {} 11 | 12 | EndpointHandler::~EndpointHandler() 13 | { 14 | if(handle) 15 | { 16 | if(connected) 17 | Log::infof("Closed endpoint connection with %s:%hu", (const char*)Socket::inetNtoA(Socket::loopbackAddr), port); 18 | server.close(*handle); 19 | } 20 | } 21 | 22 | bool EndpointHandler::connect(uint16 port) 23 | { 24 | ASSERT(!handle); 25 | Log::infof("Establishing endpoint connection with %s:%hu...", (const char*)Socket::inetNtoA(Socket::loopbackAddr), port); 26 | handle = server.connect(Socket::loopbackAddr, port, this); 27 | if(!handle) 28 | return false; 29 | this->port = port; 30 | return true; 31 | } 32 | 33 | void EndpointHandler::sendData(byte* data, size_t size) 34 | { 35 | if(connected) 36 | { 37 | size_t postponed; 38 | if(server.write(*handle, data, size, &postponed) && postponed) 39 | clientHandler.sendSuspendEntry(connectionId); 40 | } 41 | else 42 | { 43 | sendBuffer.append(data, size); 44 | clientHandler.sendSuspendEntry(connectionId); 45 | } 46 | } 47 | 48 | void EndpointHandler::suspend() 49 | { 50 | suspended = true; 51 | server.suspend(*handle); 52 | } 53 | 54 | void EndpointHandler::resume() 55 | { 56 | suspended = false; 57 | if(!suspendedByDownlink) 58 | server.resume(*handle); 59 | } 60 | 61 | void EndpointHandler::suspendByDownlink() 62 | { 63 | suspendedByDownlink = true; 64 | server.suspend(*handle); 65 | } 66 | 67 | void EndpointHandler::resumeByDownlink() 68 | { 69 | suspendedByDownlink = false; 70 | if(!suspended) 71 | server.resume(*handle); 72 | } 73 | 74 | void EndpointHandler::openedClient() 75 | { 76 | Log::infof("Established endpoint connection with %s:%hu", (const char*)Socket::inetNtoA(Socket::loopbackAddr), port); 77 | 78 | connected = true; 79 | if(!sendBuffer.isEmpty()) 80 | { 81 | server.write(*handle, sendBuffer, sendBuffer.size()); 82 | sendBuffer.free(); 83 | clientHandler.sendResumeEntry(connectionId); 84 | } 85 | } 86 | 87 | void EndpointHandler::abolishedClient() 88 | { 89 | Log::infof("Could not establish endpoint connection with %s:%hu: %s", (const char*)Socket::inetNtoA(Socket::loopbackAddr), port, (const char*)Socket::getErrorString()); 90 | 91 | clientHandler.removeEndpoint(connectionId); 92 | } 93 | 94 | void EndpointHandler::closedClient() 95 | { 96 | clientHandler.removeEndpoint(connectionId); 97 | } 98 | 99 | void EndpointHandler::readClient() 100 | { 101 | byte buffer[RECV_BUFFER_SIZE]; 102 | size_t size; 103 | if(server.read(*handle, buffer, sizeof(buffer), size)) 104 | clientHandler.sendDataToDownlink(connectionId, buffer, size); 105 | } 106 | 107 | void EndpointHandler::writeClient() 108 | { 109 | clientHandler.sendResumeEntry(connectionId); 110 | } 111 | -------------------------------------------------------------------------------- /Src/Client/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ClientHandler.h" 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | uint16 uplinkPort = 1231; 13 | String secret("Gr33nshoes"); 14 | String address; 15 | String logFile; 16 | 17 | // parse parameters 18 | { 19 | Process::Option options[] = { 20 | {'b', "daemon", Process::argumentFlag | Process::optionalFlag}, 21 | {'s', "secret", Process::argumentFlag}, 22 | {'h', "help", Process::optionFlag}, 23 | }; 24 | Process::Arguments arguments(argc, argv, options); 25 | int character; 26 | String argument; 27 | while(arguments.read(character, argument)) 28 | switch(character) 29 | { 30 | case 'b': 31 | logFile = argument.isEmpty() ? String("invtunc.log") : argument; 32 | break; 33 | case 's': 34 | secret = argument; 35 | break; 36 | case 0: 37 | address = argument; 38 | break; 39 | case '?': 40 | Console::errorf("Unknown option: %s.\n", (const char*)argument); 41 | return -1; 42 | case ':': 43 | Console::errorf("Option %s required an argument.\n", (const char*)argument); 44 | return -1; 45 | default: 46 | Console::errorf("Usage: %s [-b] :\n\ 47 | -b, --daemon[=] Detach from calling shell and write output to .\n\ 48 | -s, --secret= Set passphrase to protect the uplink connection.\n", argv[0]); 49 | return -1; 50 | } 51 | } 52 | 53 | #ifndef _WIN32 54 | if(!logFile.isEmpty()) 55 | { 56 | Log::infof("Starting as daemon..."); 57 | if(!Process::daemonize(logFile)) 58 | { 59 | Log::errorf("error: Could not daemonize process: %s", (const char*)Error::getErrorString()); 60 | return -1; 61 | } 62 | } 63 | #endif 64 | 65 | // start select loop 66 | Server server; 67 | server.setKeepAlive(true); 68 | server.setNoDelay(true); 69 | server.setSendBufferSize(SEND_BUFFER_SIZE); 70 | server.setReceiveBufferSize(RECV_BUFFER_SIZE); 71 | uint32 addr = Socket::inetAddr(address, &uplinkPort); 72 | ClientHandler clientHandler(server); 73 | if(!clientHandler.connect(addr, uplinkPort, secret)) 74 | { 75 | Log::errorf("Could not connect to %s:%hu: %s", (const char*)address, uplinkPort, (const char*)Socket::getErrorString()); 76 | return -1; 77 | } 78 | for(Server::Event event; server.poll(event);) 79 | { 80 | Callback* callback = (Callback*)event.userData; 81 | switch(event.type) 82 | { 83 | case Server::Event::failType: 84 | callback->abolishedClient(); 85 | break; 86 | case Server::Event::openType: 87 | callback->openedClient(); 88 | break; 89 | case Server::Event::readType: 90 | callback->readClient(); 91 | break; 92 | case Server::Event::writeType: 93 | callback->writeClient(); 94 | break; 95 | case Server::Event::closeType: 96 | callback->closedClient(); 97 | break; 98 | case Server::Event::acceptType: 99 | callback->acceptClient(*event.handle); 100 | break; 101 | case Server::Event::timerType: 102 | callback->executeTimer(); 103 | break; 104 | } 105 | } 106 | Log::errorf("Could not run poll loop: %s", (const char*)Socket::getErrorString()); 107 | return -1; 108 | } 109 | -------------------------------------------------------------------------------- /Src/Client/ClientHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ClientHandler.h" 7 | #include "EndpointHandler.h" 8 | #include "DownlinkHandler.h" 9 | 10 | ClientHandler::ClientHandler(Server& server) : 11 | server(server), downlink(0), suspendedAlldEnpoints(false), reconnectTimer(0) {} 12 | 13 | ClientHandler::~ClientHandler() 14 | { 15 | for(HashMap::Iterator i = endpoints.begin(), end = endpoints.end(); i != end; ++i) 16 | delete *i; 17 | delete downlink; 18 | } 19 | 20 | bool ClientHandler::connect(uint32 addr, uint16 port, const String& secret) 21 | { 22 | ASSERT(!downlink); 23 | this->addr = addr; 24 | this->port = port; 25 | this->secret = secret; 26 | downlink = new DownlinkHandler(*this, server); 27 | if(!downlink->connect(addr, port)) 28 | { 29 | delete downlink; 30 | downlink = 0; 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | void ClientHandler::executeTimer() 37 | { 38 | //Console::printf("Executed timer\n"); 39 | ASSERT(!downlink); 40 | if(connect(addr, port, secret)) 41 | { 42 | if(reconnectTimer) 43 | { 44 | server.close(*reconnectTimer); 45 | reconnectTimer = 0; 46 | } 47 | } 48 | } 49 | 50 | bool ClientHandler::removeDownlink() 51 | { 52 | if(!downlink) 53 | return false; 54 | delete downlink; 55 | downlink = 0; 56 | 57 | for(HashMap::Iterator i = endpoints.begin(), end = endpoints.end(); i != end; ++i) 58 | delete *i; 59 | endpoints.clear(), 60 | 61 | reconnectTimer = server.createTimer(10 * 1000, this); // start reconnect timer 62 | return true; 63 | } 64 | 65 | bool ClientHandler::createEndpoint(uint32 connectionId, uint16 port) 66 | { 67 | EndpointHandler* endpoint = new EndpointHandler(*this, server, connectionId); 68 | if(!endpoint->connect(port)) 69 | { 70 | delete endpoint; 71 | return false; 72 | } 73 | endpoints.append(connectionId, endpoint); 74 | return true; 75 | } 76 | 77 | bool ClientHandler::removeEndpoint(uint32 connectionId) 78 | { 79 | HashMap::Iterator it = endpoints.find(connectionId); 80 | if(it == endpoints.end()) 81 | return false; 82 | delete *it; 83 | endpoints.remove(it); 84 | 85 | if(downlink) 86 | downlink->sendDisconnect(connectionId); 87 | return true; 88 | } 89 | 90 | bool ClientHandler::sendDataToDownlink(uint32 connectionId, byte* data, size_t size) 91 | { 92 | if(!downlink) 93 | return false; 94 | downlink->sendData(connectionId, data, size); 95 | return true; 96 | } 97 | 98 | bool ClientHandler::sendDataToEndpoint(uint32 connectionId, byte* data, size_t size) 99 | { 100 | HashMap::Iterator it = endpoints.find(connectionId); 101 | if(it == endpoints.end()) 102 | return false; 103 | EndpointHandler* endpoint = *it; 104 | endpoint->sendData(data, size); 105 | return true; 106 | } 107 | 108 | void ClientHandler::sendSuspendEntry(uint32 connectionId) 109 | { 110 | if(!downlink) 111 | return; 112 | downlink->sendSuspend(connectionId); 113 | } 114 | 115 | void ClientHandler::sendResumeEntry(uint32 connectionId) 116 | { 117 | if(!downlink) 118 | return; 119 | downlink->sendResume(connectionId); 120 | } 121 | 122 | void ClientHandler::suspendEndpoint(uint32 connectionId) 123 | { 124 | HashMap::Iterator it = endpoints.find(connectionId); 125 | if(it == endpoints.end()) 126 | return; 127 | EndpointHandler* endpoint = *it; 128 | endpoint->suspendByDownlink(); 129 | } 130 | 131 | void ClientHandler::resumeEndpoint(uint32 connectionId) 132 | { 133 | HashMap::Iterator it = endpoints.find(connectionId); 134 | if(it == endpoints.end()) 135 | return; 136 | EndpointHandler* endpoint = *it; 137 | endpoint->resumeByDownlink(); 138 | } 139 | 140 | void ClientHandler::suspendAllEndpoints() 141 | { 142 | if(suspendedAlldEnpoints) 143 | return; 144 | for(HashMap::Iterator i = endpoints.begin(), end = endpoints.end(); i != end; ++i) 145 | (*i)->suspend(); 146 | suspendedAlldEnpoints = true; 147 | } 148 | 149 | void ClientHandler::resumeAllEndpoints() 150 | { 151 | if(!suspendedAlldEnpoints) 152 | return; 153 | for(HashMap::Iterator i = endpoints.begin(), end = endpoints.end(); i != end; ++i) 154 | (*i)->resume(); 155 | suspendedAlldEnpoints = false; 156 | } 157 | -------------------------------------------------------------------------------- /Src/Server/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ServerHandler.h" 10 | 11 | int main(int argc, char* argv[]) 12 | { 13 | String listenAddr; 14 | uint16 uplinkPort = 1231; 15 | String secret("Gr33nshoes"); 16 | List ports; 17 | String logFile; 18 | 19 | // parse parameters 20 | { 21 | Process::Option options[] = { 22 | {'b', "daemon", Process::argumentFlag | Process::optionalFlag}, 23 | {'l', "listen", Process::argumentFlag}, 24 | {'s', "secret", Process::argumentFlag}, 25 | {'h', "help", Process::optionFlag}, 26 | }; 27 | Process::Arguments arguments(argc, argv, options); 28 | int character; 29 | String argument; 30 | while(arguments.read(character, argument)) 31 | switch(character) 32 | { 33 | case 'b': 34 | logFile = argument.isEmpty() ? String("invtuns.log") : argument; 35 | break; 36 | case 'l': 37 | listenAddr = argument; 38 | break; 39 | case 's': 40 | secret = argument; 41 | break; 42 | case 0: 43 | ports.append(argument); 44 | break; 45 | case '?': 46 | Console::errorf("Unknown option: %s.\n", (const char*)argument); 47 | return -1; 48 | case ':': 49 | Console::errorf("Option %s required an argument.\n", (const char*)argument); 50 | return -1; 51 | default: 52 | Console::errorf("Usage: %s [-b] [:][-] [...]\n\ 53 | -b, --daemon[=] Detach from calling shell and write output to .\n\ 54 | -l, --listen=: Set listen interface IP address and port.\n\ 55 | -s, --secret= Set passphrase to protect the uplink connection.\n", argv[0]); 56 | return -1; 57 | } 58 | } 59 | 60 | #ifndef _WIN32 61 | if(!logFile.isEmpty()) 62 | { 63 | Log::infof("Starting as daemon..."); 64 | if(!Process::daemonize(logFile)) 65 | { 66 | Log::errorf("Could not daemonize process: %s", (const char*)Error::getErrorString()); 67 | return -1; 68 | } 69 | } 70 | #endif 71 | 72 | // start server 73 | Server server; 74 | server.setKeepAlive(true); 75 | server.setNoDelay(true); 76 | server.setSendBufferSize(SEND_BUFFER_SIZE); 77 | server.setReceiveBufferSize(RECV_BUFFER_SIZE); 78 | ServerHandler serverHandler(server); 79 | uint32 ip = Socket::inetAddr(listenAddr, &uplinkPort); 80 | if(!serverHandler.listen(ip, uplinkPort, secret)) 81 | { 82 | Log::errorf("Could not listen on port %hu: %s", uplinkPort, (const char*)Socket::getErrorString()); 83 | return -1; 84 | } 85 | Log::infof("Listening for uplink on port %hu...", uplinkPort); 86 | for (List::Iterator i = ports.begin(), end = ports.end(); i != end; ++i) 87 | { 88 | String argument = *i; 89 | const char* sep = argument.find('-'); 90 | uint16 mappedPort = 0; 91 | if(sep) 92 | { 93 | mappedPort = String::toUInt(sep + 1); 94 | argument.resize(sep - (const char*)argument); 95 | } 96 | uint16 port = 0; 97 | uint32 addr = Socket::inetAddr(argument, &port); 98 | if(!sep) 99 | mappedPort = port; 100 | if(!serverHandler.listen(addr, port, mappedPort)) 101 | { 102 | Log::errorf("Could not listen on port %hu: %s", port, (const char*)Socket::getErrorString()); 103 | return -1; 104 | } 105 | Log::infof("Listening for entries on port %hu...", port); 106 | } 107 | 108 | for(Server::Event event; server.poll(event);) 109 | { 110 | Callback* callback = (Callback*)event.userData; 111 | switch(event.type) 112 | { 113 | case Server::Event::failType: 114 | callback->abolishedClient(); 115 | break; 116 | case Server::Event::openType: 117 | callback->openedClient(); 118 | break; 119 | case Server::Event::readType: 120 | callback->readClient(); 121 | break; 122 | case Server::Event::writeType: 123 | callback->writeClient(); 124 | break; 125 | case Server::Event::closeType: 126 | callback->closedClient(); 127 | break; 128 | case Server::Event::acceptType: 129 | callback->acceptClient(*event.handle); 130 | break; 131 | case Server::Event::timerType: 132 | callback->executeTimer(); 133 | break; 134 | } 135 | } 136 | Log::errorf("Could not run poll loop: %s", (const char*)Socket::getErrorString()); 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /Src/Server/ServerHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "ServerHandler.h" 6 | #include "UplinkHandler.h" 7 | #include "EntryHandler.h" 8 | 9 | ServerHandler::ServerHandler(Server& server) : 10 | server(server), tunnelListener(0), uplink(0), nextConnectionId(1), suspendedAllEntries(false) {} 11 | 12 | ServerHandler::~ServerHandler() 13 | { 14 | for(HashMap::Iterator i = entries.begin(), end = entries.end(); i != end; ++i) 15 | delete *i; 16 | delete uplink; 17 | if(tunnelListener) 18 | server.close(*tunnelListener); 19 | for(HashMap::Iterator i = inboundListeners.begin(), end = inboundListeners.end(); i != end; ++i) 20 | server.close(*i.key()); 21 | } 22 | 23 | bool ServerHandler::listen(uint32 addr, uint16 port, const String& secret) 24 | { 25 | if(tunnelListener) 26 | return false; 27 | this->secret = secret; 28 | tunnelListener = server.listen(addr, port, this); 29 | if(!tunnelListener) 30 | return false; 31 | return true; 32 | } 33 | 34 | bool ServerHandler::listen(uint32 addr, uint16 port, uint16 mappedPort) 35 | { 36 | Server::Handle* handle = server.listen(addr, port, this); 37 | if(!handle) 38 | return false; 39 | inboundListeners.append(handle, mappedPort); 40 | return true; 41 | } 42 | 43 | bool ServerHandler::removeUplink() 44 | { 45 | if(!uplink) 46 | return false; 47 | delete uplink; 48 | uplink= 0; 49 | 50 | for(HashMap::Iterator i = entries.begin(), end = entries.end(); i != end; ++i) 51 | delete *i; 52 | entries.clear(); 53 | return true; 54 | } 55 | 56 | bool ServerHandler::removeEntry(uint32 connectionId) 57 | { 58 | HashMap::Iterator it = entries.find(connectionId); 59 | if(it == entries.end()) 60 | return false; 61 | delete *it; 62 | entries.remove(it); 63 | 64 | if(uplink) 65 | uplink->sendDisconnect(connectionId); 66 | return true; 67 | } 68 | 69 | bool ServerHandler::sendDataToEntry(uint32 connectionId, byte* data, size_t size) 70 | { 71 | HashMap::Iterator it = entries.find(connectionId); 72 | if(it == entries.end()) 73 | return false; 74 | EntryHandler* entry = *it; 75 | entry->sendData(data, size); 76 | return true; 77 | } 78 | 79 | bool ServerHandler::sendDataToUplink(uint32 connectionId, byte* data, size_t size) 80 | { 81 | if(!uplink) 82 | return false; 83 | return uplink->sendData(connectionId, data, size); 84 | } 85 | 86 | void ServerHandler::sendSuspendEndpoint(uint32 connectionId) 87 | { 88 | if(!uplink) 89 | return; 90 | uplink->sendSuspend(connectionId); 91 | } 92 | 93 | void ServerHandler::sendResumeEndpoint(uint32 connectionId) 94 | { 95 | if(!uplink) 96 | return; 97 | uplink->sendResume(connectionId); 98 | } 99 | 100 | void ServerHandler::suspendEntry(uint32 connectionId) 101 | { 102 | HashMap::Iterator it = entries.find(connectionId); 103 | if(it == entries.end()) 104 | return; 105 | EntryHandler* entry = *it; 106 | entry->suspendByUplink(); 107 | } 108 | 109 | void ServerHandler::resumeEntry(uint32 connectionId) 110 | { 111 | HashMap::Iterator it = entries.find(connectionId); 112 | if(it == entries.end()) 113 | return; 114 | EntryHandler* entry = *it; 115 | entry->resumeByUplink(); 116 | } 117 | 118 | void ServerHandler::suspendAllEntries() 119 | { 120 | if(suspendedAllEntries) 121 | return; 122 | for(HashMap::Iterator i = entries.begin(), end = entries.end(); i != end; ++i) 123 | (*i)->suspend(); 124 | suspendedAllEntries = true; 125 | } 126 | 127 | void ServerHandler::resumeAllEntries() 128 | { 129 | if(!suspendedAllEntries) 130 | return; 131 | for(HashMap::Iterator i = entries.begin(), end = entries.end(); i != end; ++i) 132 | (*i)->resume(); 133 | suspendedAllEntries = false; 134 | } 135 | 136 | void ServerHandler::acceptClient(Server::Handle& listenerHandle) 137 | { 138 | if(&listenerHandle == tunnelListener) 139 | { 140 | if(uplink) 141 | { 142 | Server::Handle* handle = server.accept(listenerHandle, 0); 143 | if(handle) 144 | { 145 | server.close(*handle); 146 | return; 147 | } 148 | } 149 | 150 | uplink = new UplinkHandler(*this, server); 151 | if(!uplink->accept(listenerHandle)) 152 | { 153 | delete uplink; 154 | uplink = 0; 155 | return; 156 | } 157 | } 158 | else 159 | { 160 | if(!uplink) 161 | { 162 | Server::Handle* handle = server.accept(listenerHandle, 0); 163 | if(handle) 164 | { 165 | server.close(*handle); 166 | return; 167 | } 168 | } 169 | uint32 connectionId = nextConnectionId++; 170 | EntryHandler* entry = new EntryHandler(*this, server, connectionId); 171 | if(!entry->accept(listenerHandle)) 172 | { 173 | delete entry; 174 | return; 175 | } 176 | uint16 mappedPort = mapPort(listenerHandle); 177 | uplink->sendConnect(connectionId, mappedPort); 178 | entries.append(connectionId, entry); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /Src/Server/UplinkHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "UplinkHandler.h" 9 | #include "ServerHandler.h" 10 | 11 | UplinkHandler::UplinkHandler(ServerHandler& serverHandler, Server& server) 12 | : serverHandler(serverHandler), server(server), handle(0), authed(false) {} 13 | 14 | UplinkHandler::~UplinkHandler() 15 | { 16 | if(handle) 17 | { 18 | Log::infof("Closed uplink connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 19 | server.close(*handle); 20 | } 21 | } 22 | 23 | bool UplinkHandler::accept(Server::Handle& listenerHandle) 24 | { 25 | ASSERT(!handle); 26 | handle = server.accept(listenerHandle, this, &addr, &port); 27 | if(!handle) 28 | return false; 29 | Log::infof("Accepted uplink connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 30 | return true; 31 | } 32 | 33 | bool UplinkHandler::sendConnect(uint32 connectionId, uint16 port) 34 | { 35 | if(!authed) 36 | return false; 37 | 38 | Protocol::ConnectMessage connectMessage; 39 | connectMessage.size = sizeof(connectMessage); 40 | connectMessage.messageType = Protocol::connect; 41 | connectMessage.connectionId = connectionId; 42 | connectMessage.port = port; 43 | server.write(*handle, (const byte*)&connectMessage, sizeof(connectMessage)); 44 | return true; 45 | } 46 | 47 | bool UplinkHandler::sendDisconnect(uint32 connectionId) 48 | { 49 | if(!authed) 50 | return false; 51 | 52 | Protocol::DisconnectMessage disconnectMessage; 53 | disconnectMessage.size = sizeof(disconnectMessage); 54 | disconnectMessage.messageType = Protocol::disconnect; 55 | disconnectMessage.connectionId = connectionId; 56 | server.write(*handle, (const byte*)&disconnectMessage, sizeof(disconnectMessage)); 57 | return true; 58 | } 59 | 60 | bool UplinkHandler::sendData(uint32 connectionId, const byte* data, size_t size) 61 | { 62 | if(!authed) 63 | return false; 64 | 65 | lz4Buffer.resize(sizeof(Protocol::DataMessage) + LZ4_compressBound(size)); 66 | int compressedSize = LZ4_compress((const char*)data, (char*)(byte*)lz4Buffer + sizeof(Protocol::DataMessage), size); 67 | if(compressedSize <= 0) 68 | { 69 | serverHandler.removeUplink(); 70 | return false; 71 | } 72 | 73 | Protocol::DataMessage* dataMessage = (Protocol::DataMessage*)(byte*)lz4Buffer; 74 | dataMessage->size = sizeof(Protocol::DataMessage) + compressedSize; 75 | dataMessage->messageType = Protocol::data; 76 | dataMessage->connectionId = connectionId; 77 | dataMessage->originalSize = size; 78 | size_t postponed; 79 | if(server.write(*handle, (const byte*)dataMessage, dataMessage->size, &postponed) && postponed) 80 | serverHandler.suspendAllEntries(); 81 | return true; 82 | } 83 | 84 | bool UplinkHandler::sendSuspend(uint32 connectionId) 85 | { 86 | if(!authed) 87 | return false; 88 | 89 | Protocol::SuspendMessage suspendMessage; 90 | suspendMessage.size = sizeof(suspendMessage); 91 | suspendMessage.messageType = Protocol::suspend; 92 | suspendMessage.connectionId = connectionId; 93 | server.write(*handle, (const byte*)&suspendMessage, sizeof(suspendMessage)); 94 | return true; 95 | } 96 | 97 | bool UplinkHandler::sendResume(uint32 connectionId) 98 | { 99 | if(!authed) 100 | return false; 101 | 102 | Protocol::ResumeMessage resumeMessage; 103 | resumeMessage.size = sizeof(resumeMessage); 104 | resumeMessage.messageType = Protocol::resume; 105 | resumeMessage.connectionId = connectionId; 106 | server.write(*handle, (const byte*)&resumeMessage, sizeof(resumeMessage)); 107 | return true; 108 | } 109 | 110 | void UplinkHandler::handleMessage(Protocol::MessageType messageType, byte* data, size_t size) 111 | { 112 | switch(messageType) 113 | { 114 | case Protocol::auth: 115 | if(!authed && size >= sizeof(Protocol::AuthMessage)) 116 | handleAuthMessage(*(Protocol::AuthMessage*)data); 117 | break; 118 | case Protocol::disconnect: 119 | if(authed && size >= sizeof(Protocol::DisconnectMessage)) 120 | handleDisconnectMessage(*(Protocol::DisconnectMessage*)data); 121 | break; 122 | case Protocol::data: 123 | if(authed && size >= sizeof(Protocol::DataMessage)) 124 | handleDataMessage(*(Protocol::DataMessage*)data, data + sizeof(Protocol::DataMessage), size - sizeof(Protocol::DataMessage)); 125 | break; 126 | case Protocol::suspend: 127 | if(authed && size >= sizeof(Protocol::SuspendMessage)) 128 | handleSuspendMessage(*(Protocol::SuspendMessage*)data); 129 | break; 130 | case Protocol::resume: 131 | if(authed && size >= sizeof(Protocol::ResumeMessage)) 132 | handleResumeMessage(*(Protocol::ResumeMessage*)data); 133 | break; 134 | default: 135 | break; 136 | } 137 | } 138 | 139 | void UplinkHandler::handleAuthMessage(Protocol::AuthMessage& authMessage) 140 | { 141 | if(Protocol::getString(authMessage.secret) != serverHandler.getSecret()) 142 | { 143 | serverHandler.removeUplink(); 144 | return; // invalid secret 145 | } 146 | authed = true; 147 | Protocol::Header response; 148 | response.size = sizeof(response); 149 | response.messageType = Protocol::authResponse; 150 | server.write(*handle, (const byte*)&response, sizeof(response)); 151 | } 152 | 153 | void UplinkHandler::handleDisconnectMessage(const Protocol::DisconnectMessage& disconnectMessage) 154 | { 155 | serverHandler.removeEntry(disconnectMessage.connectionId); 156 | } 157 | 158 | void UplinkHandler::handleDataMessage(const Protocol::DataMessage& message, byte* data, size_t size) 159 | { 160 | //Console::printf("recvData: compressedSize=%d, originalSize=%d\n", (int)size, (int)message.originalSize); 161 | 162 | int originalSize = message.originalSize; 163 | lz4Buffer.resize(originalSize); 164 | if(LZ4_decompress_safe((const char*)data,(char*)(byte*)lz4Buffer, size, originalSize) != originalSize) 165 | { 166 | serverHandler.removeUplink(); 167 | return; 168 | } 169 | 170 | serverHandler.sendDataToEntry(message.connectionId, lz4Buffer, originalSize); 171 | } 172 | 173 | void UplinkHandler::handleSuspendMessage(const Protocol::SuspendMessage& suspendMessage) 174 | { 175 | serverHandler.suspendEntry(suspendMessage.connectionId); 176 | } 177 | 178 | void UplinkHandler::handleResumeMessage(const Protocol::ResumeMessage& resumeMessage) 179 | { 180 | serverHandler.resumeEntry(resumeMessage.connectionId); 181 | } 182 | 183 | void UplinkHandler::readClient() 184 | { 185 | size_t size; 186 | size_t oldSize = readBuffer.size(); 187 | readBuffer.resize(LZ4_compressBound(RECV_BUFFER_SIZE) + sizeof(Protocol::DataMessage) + 1); 188 | if(!server.read(*handle, (byte*)readBuffer + oldSize, readBuffer.capacity() - oldSize, size)) 189 | return; 190 | size += oldSize; 191 | readBuffer.resize(size); 192 | 193 | byte* pos = readBuffer; 194 | while(size > 0) 195 | { 196 | if(size < sizeof(Protocol::Header)) 197 | break; 198 | Protocol::Header* header = (Protocol::Header*)pos; 199 | if(header->size < sizeof(Protocol::Header)) 200 | { 201 | serverHandler.removeUplink(); 202 | return; 203 | } 204 | if(size < header->size) 205 | break; 206 | handleMessage((Protocol::MessageType)header->messageType, pos, header->size); 207 | pos += header->size; 208 | size -= header->size; 209 | } 210 | readBuffer.removeFront(pos - (byte*)readBuffer); 211 | if(size > LZ4_compressBound(RECV_BUFFER_SIZE) + sizeof(Protocol::DataMessage)) 212 | { 213 | serverHandler.removeUplink(); 214 | return; 215 | } 216 | } 217 | 218 | void UplinkHandler::writeClient() 219 | { 220 | serverHandler.resumeAllEntries(); 221 | } 222 | 223 | void UplinkHandler::closedClient() 224 | { 225 | serverHandler.removeUplink(); 226 | } 227 | -------------------------------------------------------------------------------- /Src/Client/DownlinkHandler.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "DownlinkHandler.h" 9 | #include "ClientHandler.h" 10 | 11 | DownlinkHandler::DownlinkHandler(ClientHandler& clientHandler, Server& server) : 12 | clientHandler(clientHandler), server(server), handle(0), connected(false), authed(false) {} 13 | 14 | DownlinkHandler::~DownlinkHandler() 15 | { 16 | if(handle) 17 | { 18 | if(connected) 19 | Log::infof("Closed downlink connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 20 | server.close(*handle); 21 | } 22 | } 23 | 24 | bool DownlinkHandler::connect(uint32 addr, uint16 port) 25 | { 26 | ASSERT(!handle); 27 | Log::infof("Establishing downlink connection with %s:%hu...", (const char*)Socket::inetNtoA(addr), port); 28 | handle = server.connect(addr, port, this); 29 | if(!handle) 30 | return false; 31 | this->addr = addr; 32 | this->port = port; 33 | return true; 34 | } 35 | 36 | bool DownlinkHandler::sendDisconnect(uint32 connectionId) 37 | { 38 | if(!authed) 39 | return false; 40 | 41 | Protocol::DisconnectMessage disconnectMessage; 42 | disconnectMessage.size = sizeof(disconnectMessage); 43 | disconnectMessage.messageType = Protocol::disconnect; 44 | disconnectMessage.connectionId = connectionId; 45 | server.write(*handle, (const byte*)&disconnectMessage, sizeof(disconnectMessage)); 46 | return true; 47 | } 48 | 49 | bool DownlinkHandler::sendData(uint32 connectionId, byte* data, size_t size) 50 | { 51 | if(!authed) 52 | return false; 53 | 54 | lz4Buffer.resize(sizeof(Protocol::DataMessage) + LZ4_compressBound(size)); 55 | int compressedSize = LZ4_compress((const char*)data, (char*)(byte*)lz4Buffer + sizeof(Protocol::DataMessage), size); 56 | if(compressedSize <= 0) 57 | { 58 | clientHandler.removeDownlink(); 59 | return false; 60 | } 61 | 62 | Protocol::DataMessage* dataMessage = (Protocol::DataMessage*)(byte*)lz4Buffer; 63 | dataMessage->size = sizeof(Protocol::DataMessage) + compressedSize; 64 | dataMessage->messageType = Protocol::data; 65 | dataMessage->connectionId = connectionId; 66 | dataMessage->originalSize = size; 67 | size_t postponed; 68 | if(server.write(*handle, (const byte*)dataMessage, dataMessage->size, &postponed) && postponed) 69 | clientHandler.suspendAllEndpoints(); 70 | return true; 71 | } 72 | 73 | bool DownlinkHandler::sendSuspend(uint32 connectionId) 74 | { 75 | if(!authed) 76 | return false; 77 | 78 | Protocol::SuspendMessage suspendMessage; 79 | suspendMessage.size = sizeof(suspendMessage); 80 | suspendMessage.messageType = Protocol::suspend; 81 | suspendMessage.connectionId = connectionId; 82 | server.write(*handle, (const byte*)&suspendMessage, sizeof(suspendMessage)); 83 | return true; 84 | } 85 | 86 | bool DownlinkHandler::sendResume(uint32 connectionId) 87 | { 88 | if(!authed) 89 | return false; 90 | 91 | Protocol::ResumeMessage resumeMessage; 92 | resumeMessage.size = sizeof(resumeMessage); 93 | resumeMessage.messageType = Protocol::resume; 94 | resumeMessage.connectionId = connectionId; 95 | server.write(*handle, (const byte*)&resumeMessage, sizeof(resumeMessage)); 96 | return true; 97 | } 98 | 99 | void DownlinkHandler::openedClient() 100 | { 101 | Log::infof("Established downlink connection with %s:%hu", (const char*)Socket::inetNtoA(addr), port); 102 | 103 | connected = true; 104 | 105 | Protocol::AuthMessage authMessage; 106 | authMessage.size = sizeof(authMessage); 107 | authMessage.messageType = Protocol::auth; 108 | Protocol::setString(authMessage.secret, clientHandler.getSecret()); 109 | server.write(*handle, (const byte*)&authMessage, sizeof(authMessage)); 110 | } 111 | 112 | void DownlinkHandler::abolishedClient() 113 | { 114 | Log::infof("Could not establish downlink connection with %s:%hu: %s", (const char*)Socket::inetNtoA(addr), port, (const char*)Socket::getErrorString()); 115 | 116 | clientHandler.removeDownlink(); 117 | } 118 | 119 | void DownlinkHandler::handleMessage(Protocol::MessageType messageType, byte* data, size_t size) 120 | { 121 | switch(messageType) 122 | { 123 | case Protocol::authResponse: 124 | if(!authed) 125 | authed = true; 126 | break; 127 | case Protocol::connect: 128 | if(authed && size >= sizeof(Protocol::ConnectMessage)) 129 | handleConnectMessage(*(Protocol::ConnectMessage*)data); 130 | break; 131 | case Protocol::disconnect: 132 | if(authed && size >= sizeof(Protocol::DisconnectMessage)) 133 | handleDisconnectMessage(*(Protocol::DisconnectMessage*)data); 134 | break; 135 | case Protocol::data: 136 | if(authed && size >= sizeof(Protocol::DataMessage)) 137 | handleDataMessage(*(Protocol::DataMessage*)data, data + sizeof(Protocol::DataMessage), size - sizeof(Protocol::DataMessage)); 138 | break; 139 | case Protocol::suspend: 140 | if(authed && size >= sizeof(Protocol::SuspendMessage)) 141 | handleSuspendMessage(*(Protocol::SuspendMessage*)data); 142 | break; 143 | case Protocol::resume: 144 | if(authed && size >= sizeof(Protocol::ResumeMessage)) 145 | handleResumeMessage(*(Protocol::ResumeMessage*)data); 146 | break; 147 | default: 148 | break; 149 | } 150 | } 151 | 152 | void DownlinkHandler::handleConnectMessage(const Protocol::ConnectMessage& connect) 153 | { 154 | if(!clientHandler.createEndpoint(connect.connectionId, connect.port)) 155 | sendDisconnect(connect.connectionId); 156 | } 157 | 158 | void DownlinkHandler::handleDisconnectMessage(const Protocol::DisconnectMessage& disconnect) 159 | { 160 | clientHandler.removeEndpoint(disconnect.connectionId); 161 | } 162 | 163 | void DownlinkHandler::handleDataMessage(const Protocol::DataMessage& message, byte* data, size_t size) 164 | { 165 | int originalSize = message.originalSize; 166 | lz4Buffer.resize(originalSize); 167 | if(LZ4_decompress_safe((const char*)data,(char*)(byte*)lz4Buffer, size, originalSize) != originalSize) 168 | { 169 | clientHandler.removeDownlink(); 170 | return; 171 | } 172 | 173 | clientHandler.sendDataToEndpoint(message.connectionId, lz4Buffer, originalSize); 174 | } 175 | 176 | void DownlinkHandler::handleSuspendMessage(const Protocol::SuspendMessage& suspendMessage) 177 | { 178 | clientHandler.suspendEndpoint(suspendMessage.connectionId); 179 | } 180 | 181 | void DownlinkHandler::handleResumeMessage(const Protocol::ResumeMessage& resumeMessage) 182 | { 183 | clientHandler.resumeEndpoint(resumeMessage.connectionId); 184 | } 185 | 186 | void DownlinkHandler::readClient() 187 | { 188 | size_t size; 189 | size_t oldSize = readBuffer.size(); 190 | readBuffer.resize(LZ4_compressBound(RECV_BUFFER_SIZE) + sizeof(Protocol::DataMessage) + 1); 191 | if(!server.read(*handle, (byte*)readBuffer + oldSize, readBuffer.capacity() - oldSize, size)) 192 | return; 193 | size += oldSize; 194 | readBuffer.resize(size); 195 | 196 | byte* pos = readBuffer; 197 | while(size > 0) 198 | { 199 | if(size < sizeof(Protocol::Header)) 200 | break; 201 | Protocol::Header* header = (Protocol::Header*)pos; 202 | if(header->size < sizeof(Protocol::Header)) 203 | { 204 | clientHandler.removeDownlink(); 205 | return; 206 | } 207 | if(size < header->size) 208 | break; 209 | handleMessage((Protocol::MessageType)header->messageType, pos, header->size); 210 | pos += header->size; 211 | size -= header->size; 212 | } 213 | readBuffer.removeFront(pos - (byte*)readBuffer); 214 | if(size > LZ4_compressBound(RECV_BUFFER_SIZE) + sizeof(Protocol::DataMessage)) 215 | { 216 | clientHandler.removeDownlink(); 217 | return; 218 | } 219 | } 220 | 221 | void DownlinkHandler::writeClient() 222 | { 223 | clientHandler.resumeAllEndpoints(); 224 | } 225 | 226 | void DownlinkHandler::closedClient() 227 | { 228 | clientHandler.removeDownlink(); 229 | } 230 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------