From 0e90654e8ea6939e6408593d0e9a4bc56ea67231 Mon Sep 17 00:00:00 2001 From: NTX Date: Wed, 7 Mar 2012 18:35:25 +0100 Subject: [PATCH] Iniiit --- .gitignore | 14 + Application/Application.cpp | 456 ++++++++++++++++++++++++ Application/Application.h | 137 +++++++ ConfigMgr/ConfigMgr.cpp | 176 +++++++++ ConfigMgr/ConfigMgr.h | 36 ++ DataArrays/binData.cpp | 426 ++++++++++++++++++++++ DataArrays/binData.h | 128 +++++++ DataArrays/file.cpp | 102 ++++++ DataArrays/file.h | 117 ++++++ Handling/Handler.cpp | 152 ++++++++ Handling/Handler.h | 90 +++++ OLD_Makefiles/Protocol/FTP/makefile | 4 + OLD_Makefiles/Protocol/HTTP/makefile | 4 + OLD_Makefiles/Protocol/SMTP/makefile | 4 + OLD_Makefiles/Protocol/libdump/makefile | 6 + OLD_Makefiles/Protocol/makefile | 26 ++ OLD_Makefiles/README.TXT | 2 + OLD_Makefiles/makefile | 116 ++++++ Protocol/CMakeLists.txt | 4 + Protocol/FTP/Adds.cpp | 30 ++ Protocol/FTP/Adds.h | 10 + Protocol/FTP/Base.cpp | 439 +++++++++++++++++++++++ Protocol/FTP/Base.h | 21 ++ Protocol/FTP/CMakeLists.txt | 17 + Protocol/FTP/FTP.cpp | 365 +++++++++++++++++++ Protocol/FTP/FTP.h | 176 +++++++++ Protocol/FTP/FileAccessor.cpp | 80 +++++ Protocol/FTP/FileAccessor.h | 113 ++++++ Protocol/FTP/defines.h | 14 + Protocol/FTP/ftp.conf | 33 ++ Protocol/HTTP/Adds.cpp | 92 +++++ Protocol/HTTP/Adds.h | 48 +++ Protocol/HTTP/Base.cpp | 216 +++++++++++ Protocol/HTTP/CMakeLists.txt | 17 + Protocol/HTTP/HTTP.cpp | 119 +++++++ Protocol/HTTP/HTTP.h | 73 ++++ Protocol/HTTP/defines.h | 11 + Protocol/HTTP/http.conf | 24 ++ Protocol/Includes.cpp | 23 ++ Protocol/SMTP/Adds.cpp | 23 ++ Protocol/SMTP/Adds.h | 10 + Protocol/SMTP/Base.cpp | 148 ++++++++ Protocol/SMTP/Base.h | 46 +++ Protocol/SMTP/CMakeLists.txt | 17 + Protocol/SMTP/SMTP.cpp | 25 ++ Protocol/SMTP/SMTP.h | 38 ++ Protocol/SMTP/defines.h | 14 + Protocol/SMTP/smtp.conf | 3 + Protocol/libdump/CMakeLists.txt | 11 + Protocol/libdump/libdump.cpp | 9 + Protocol/libdump/libdump.h | 20 ++ Shared/Shared.cpp | 45 +++ Shared/Shared.h | 35 ++ Signal/SignalHandler.cpp | 121 +++++++ Signal/SignalHandler.h | 36 ++ SimpleLog/SimpleLog.cpp | 173 +++++++++ SimpleLog/SimpleLog.h | 35 ++ Sockets/Socket.cpp | 233 ++++++++++++ Sockets/Socket.h | 89 +++++ Sockets/SocketMgr.cpp | 115 ++++++ Sockets/SocketMgr.h | 45 +++ Threads/ThreadMgr.cpp | 320 +++++++++++++++++ Threads/ThreadMgr.h | 151 ++++++++ Utilities/Utils.cpp | 28 ++ Utilities/Utils.h | 72 ++++ config.conf | 56 +++ 66 files changed, 5839 insertions(+) create mode 100644 .gitignore create mode 100644 Application/Application.cpp create mode 100644 Application/Application.h create mode 100644 ConfigMgr/ConfigMgr.cpp create mode 100644 ConfigMgr/ConfigMgr.h create mode 100644 DataArrays/binData.cpp create mode 100644 DataArrays/binData.h create mode 100644 DataArrays/file.cpp create mode 100644 DataArrays/file.h create mode 100644 Handling/Handler.cpp create mode 100644 Handling/Handler.h create mode 100644 OLD_Makefiles/Protocol/FTP/makefile create mode 100644 OLD_Makefiles/Protocol/HTTP/makefile create mode 100644 OLD_Makefiles/Protocol/SMTP/makefile create mode 100644 OLD_Makefiles/Protocol/libdump/makefile create mode 100644 OLD_Makefiles/Protocol/makefile create mode 100644 OLD_Makefiles/README.TXT create mode 100755 OLD_Makefiles/makefile create mode 100644 Protocol/CMakeLists.txt create mode 100644 Protocol/FTP/Adds.cpp create mode 100644 Protocol/FTP/Adds.h create mode 100755 Protocol/FTP/Base.cpp create mode 100644 Protocol/FTP/Base.h create mode 100644 Protocol/FTP/CMakeLists.txt create mode 100644 Protocol/FTP/FTP.cpp create mode 100644 Protocol/FTP/FTP.h create mode 100755 Protocol/FTP/FileAccessor.cpp create mode 100755 Protocol/FTP/FileAccessor.h create mode 100644 Protocol/FTP/defines.h create mode 100644 Protocol/FTP/ftp.conf create mode 100644 Protocol/HTTP/Adds.cpp create mode 100644 Protocol/HTTP/Adds.h create mode 100755 Protocol/HTTP/Base.cpp create mode 100644 Protocol/HTTP/CMakeLists.txt create mode 100644 Protocol/HTTP/HTTP.cpp create mode 100644 Protocol/HTTP/HTTP.h create mode 100644 Protocol/HTTP/defines.h create mode 100644 Protocol/HTTP/http.conf create mode 100644 Protocol/Includes.cpp create mode 100644 Protocol/SMTP/Adds.cpp create mode 100644 Protocol/SMTP/Adds.h create mode 100755 Protocol/SMTP/Base.cpp create mode 100644 Protocol/SMTP/Base.h create mode 100644 Protocol/SMTP/CMakeLists.txt create mode 100644 Protocol/SMTP/SMTP.cpp create mode 100644 Protocol/SMTP/SMTP.h create mode 100644 Protocol/SMTP/defines.h create mode 100644 Protocol/SMTP/smtp.conf create mode 100644 Protocol/libdump/CMakeLists.txt create mode 100644 Protocol/libdump/libdump.cpp create mode 100644 Protocol/libdump/libdump.h create mode 100644 Shared/Shared.cpp create mode 100644 Shared/Shared.h create mode 100644 Signal/SignalHandler.cpp create mode 100644 Signal/SignalHandler.h create mode 100644 SimpleLog/SimpleLog.cpp create mode 100644 SimpleLog/SimpleLog.h create mode 100644 Sockets/Socket.cpp create mode 100644 Sockets/Socket.h create mode 100644 Sockets/SocketMgr.cpp create mode 100644 Sockets/SocketMgr.h create mode 100644 Threads/ThreadMgr.cpp create mode 100644 Threads/ThreadMgr.h create mode 100644 Utilities/Utils.cpp create mode 100644 Utilities/Utils.h create mode 100644 config.conf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d0ceb8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +build/ +bin/ +Server/ +*.o +*.a +*.so +*.git +*.patch +*.diff +*~ +*.h~ +*.cpp~ +.directory +.mailmap diff --git a/Application/Application.cpp b/Application/Application.cpp new file mode 100644 index 0000000..b47af1c --- /dev/null +++ b/Application/Application.cpp @@ -0,0 +1,456 @@ +#include "Application.h" + + +Application::Application(int argc, char* argv[], const char *conf): +debug(false), control(false), daemonize(false), libLoaded(false), terminate(false) +{ + _initGlobals(); + + if (argc> 0) + for (int i = 1 ; i < argc ; i++) + { + string arg = string(argv[i]); + string property, value; + refTrim(arg); + if (arg.find('=') != string::npos) + { + property = arg.substr(arg.find_first_not_of('-'), arg.find('=') - arg.find_first_not_of('-')); + refTrim(property); + value = arg.substr(arg.find('=') + 1 , string::npos); + refTrim(value); + } + else + { + property = arg.substr(arg.find_first_not_of('-'), string::npos); + value = string("1"); + } + RunOptions.insert(make_pair(property, value)); + } + + if (conf) + { + AsciiFile config(conf); + if (config) + { + char buff[1024]; + string line ; + do + { + config.getline(buff, 1024); + line = buff; + if( (line.length() > 0) && + (line[0] != '#') && (line[0] != ';') && + (line.find('=') != string::npos)) + { + refTrim(line); + string property = line.substr(0, line.find('=')); + refTrim(property); + string value = line.substr(line.find('=') + 1, string::npos); + refTrim(value); + if (property.length() && value.length()) + FileOptions.insert(make_pair(property, value)); + } + } while (!config.eof()); + } + } + ParseParams(); +} + +void Application::ParseParams() +{ + LoadConfigs(); + switch (IntConfigs[CONFIG_INT_LOG_LEVEL]) + { + case 3: + case 2: debug = true; + case 1: control = true; + } + +} + +void Application::LoadConfigs() +{ + for (register int i = 0; i < CONFIG_INT_MAX; ++i) + IntConfigs[i] = 0; + + for (register int i = 0; i < CONFIG_BOOL_MAX; ++i) + BoolConfigs[i] = false; + + for (register int i = 0; i < CONFIG_STRING_MAX; ++i) + StringConfigs[i] = string(""); + + if (FileOptions.size() > 0) + { + LoadBoolConfig("Server.Daemonize", CONFIG_BOOL_DAEMONIZE, false); + LoadBoolConfig("Server.Log", CONFIG_BOOL_LOG, true); + LoadIntConfig("Server.LogLevel", CONFIG_INT_LOG_LEVEL, 0); + + LoadIntConfig("Protocol.BindPort", CONFIG_INT_BIND_PORT, 3535); + LoadStringConfig("Protocol.BindIp", CONFIG_STRING_BIND_IP, "127.0.0.1"); + LoadStringConfig("Protocol.ProtocolName", CONFIG_STRING_PROTOCOL_NAME); + LoadStringConfig("Protocol.LibraryPath", CONFIG_STRING_LIBRARY_PATH); + LoadStringConfig("Protocol.RecvFunc", CONFIG_STRING_RECV_FUNC); + LoadStringConfig("Protocol.SendFunc", CONFIG_STRING_SEND_FUNC); + LoadStringConfig("Protocol.ConnectFunc", CONFIG_STRING_CONNECT_FUNC); + LoadStringConfig("Protocol.DisconnectFunc", CONFIG_STRING_DISCONNECT_FUNC); + LoadStringConfig("Protocol.LoadFunc", CONFIG_STRING_LOAD_FUNC); + } + + if (RunOptions.size() > 0) + { + LoadBoolRunConfig("daemonize", "d", CONFIG_BOOL_DAEMONIZE); + LoadBoolRunConfig("log", "l", CONFIG_BOOL_LOG); + LoadIntRunConfig("loglevel", "ll", CONFIG_INT_LOG_LEVEL); + } +} + +void Application::outDebugParams() const +{ + sLog->outString("CONFIG_BOOL_DAEMONIZE=%s", toString(BoolConfigs[CONFIG_BOOL_DAEMONIZE])); + sLog->outString("CONFIG_BOOL_LOG=%s", toString(BoolConfigs[CONFIG_BOOL_LOG])); + sLog->outString("CONFIG_INT_LOG_LEVEL=%d", IntConfigs[CONFIG_INT_LOG_LEVEL]); + sLog->outString("Control=%s", toString(control)); + sLog->outString("Debug=%s", toString(debug)); + sLog->outString(); + sLog->outString("CONFIG_INT_BIND_PORT=%d", IntConfigs[CONFIG_INT_BIND_PORT]); + sLog->outString("CONFIG_STRING_BIND_IP='%s'", StringConfigs[CONFIG_STRING_BIND_IP].c_str()); + sLog->outString("CONFIG_STRING_PROTOCOL_NAME='%s'", StringConfigs[CONFIG_STRING_PROTOCOL_NAME].c_str()); + sLog->outString("CONFIG_STRING_LIBRARY_PATH='%s'", StringConfigs[CONFIG_STRING_LIBRARY_PATH].c_str()); + sLog->outString("CONFIG_STRING_RECV_FUNC='%s'", StringConfigs[CONFIG_STRING_RECV_FUNC].c_str()); + sLog->outString("CONFIG_STRING_SEND_FUNC='%s'", StringConfigs[CONFIG_STRING_SEND_FUNC].c_str()); + sLog->outString("CONFIG_STRING_CONNECT_FUNC='%s'", StringConfigs[CONFIG_STRING_CONNECT_FUNC].c_str()); + sLog->outString("CONFIG_STRING_DISCONNECT_FUNC='%s'", StringConfigs[CONFIG_STRING_DISCONNECT_FUNC].c_str()); + sLog->outString("CONFIG_STRING_LOAD_FUNC='%s'", StringConfigs[CONFIG_STRING_LOAD_FUNC].c_str()); +} + +void Application::outDebugLibrary() const +{ + sLog->outString(); + sLog->outString("Library Name: %s", libLoader->GetLibraryPath()); + sLog->outString("Is Open: %s", toString(libLoader->is_open())); + sLog->outString("Is Loaded: %s", toString(libLoaded)); + sLog->outString("Recieve Function at Address: 0x%08x", proto.OnRecieve); + sLog->outString("Send Function at Address: 0x%08x", proto.OnSend); + sLog->outString("Connect Function at Address: 0x%08x", proto.OnConnect); + sLog->outString("Disconnect Function at Address: 0x%08x", proto.OnDisconnect); + sLog->outString("Load Function at Address: 0x%08x", proto.OnLoad); + sLog->outString(); +} + +void Application::LoadIntConfig(string ConfigName, uint32 Config, uint32 Default) +{ + if (FileOptions.size() > 0) + { + if (FileOptions.find(ConfigName) != FileOptions.end()) + { + stringstream s; + s.str(FileOptions[ConfigName]); + s >> IntConfigs[Config]; + } + else + IntConfigs[Config] = Default; + } +} + +void Application::LoadStringConfig(string ConfigName, uint32 Config, string Default) +{ + if (FileOptions.size() > 0) + StringConfigs[Config] = (FileOptions.find(ConfigName) != FileOptions.end() ? FileOptions[ConfigName] : Default); +} + +void Application::LoadBoolConfig(string ConfigName, uint32 Config, bool Default) +{ + if (FileOptions.size() > 0) + { + if (FileOptions.find(ConfigName) != FileOptions.end()) + { + stringstream s; + s.str(FileOptions[ConfigName]); + s >> BoolConfigs[Config]; + } + else + BoolConfigs[Config] = Default; + } +} + +void Application::LoadIntRunConfig(string ConfigName, string ShortFormat, uint32 Config) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + { + stringstream s; + s.str(RunOptions[ConfigName]); + s >> IntConfigs[Config]; + } + else + if (RunOptions.find(ShortFormat) != RunOptions.end()) + { + stringstream s; + s.str(RunOptions[ShortFormat]); + s >> IntConfigs[Config]; + } + } +} + +void Application::LoadStringRunConfig(string ConfigName, string ShortFormat, uint32 Config) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + StringConfigs[Config] = RunOptions[ConfigName]; + else + if (RunOptions.find(ShortFormat) != RunOptions.end()) + StringConfigs[Config] = RunOptions[ShortFormat]; + } +} + +void Application::LoadBoolRunConfig(string ConfigName, string ShortFormat, uint32 Config) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + { + stringstream s; + s.str(RunOptions[ConfigName]); + s >> BoolConfigs[Config]; + } + else + if (RunOptions.find(ShortFormat) != RunOptions.end()) + { + stringstream s; + s.str(RunOptions[ShortFormat]); + s >> BoolConfigs[Config]; + } + } +} + +bool Application::LoadLibrary() +{ + if (!StringConfigs[CONFIG_STRING_LIBRARY_PATH].length()) + return libLoaded = false; + + if (!libLoader->open(StringConfigs[CONFIG_STRING_LIBRARY_PATH].c_str())) + return libLoaded = false; + + if (StringConfigs[CONFIG_STRING_SEND_FUNC].length()) + proto.OnSend = onSend(libLoader->findFunc(StringConfigs[CONFIG_STRING_SEND_FUNC].c_str())) ; + + if (StringConfigs[CONFIG_STRING_RECV_FUNC].length()) + proto.OnRecieve = onRecieve(libLoader->findFunc(StringConfigs[CONFIG_STRING_RECV_FUNC].c_str())) ; + + if (StringConfigs[CONFIG_STRING_CONNECT_FUNC].length()) + proto.OnConnect = onConnect(libLoader->findFunc(StringConfigs[CONFIG_STRING_CONNECT_FUNC].c_str())); + + if (StringConfigs[CONFIG_STRING_DISCONNECT_FUNC].length()) + proto.OnDisconnect = onDisconnect(libLoader->findFunc(StringConfigs[CONFIG_STRING_DISCONNECT_FUNC].c_str())); + + if (StringConfigs[CONFIG_STRING_LOAD_FUNC].length()) + proto.OnLoad = onLoad(libLoader->findFunc(StringConfigs[CONFIG_STRING_LOAD_FUNC].c_str())); + + return libLoaded = true; +} + + +void Application::_initGlobals() +{ + sLog = new SimpleLog(control, debug, "Server.log"); + sigHandler = new SignalHandler(); + libLoader = new SharedLibrary(); + socketMgr = new ConnectionMgr(); + threadMgr = new ThreadMgr(); + handler = new PacketHandler(); +} + +void Application::_uninitGlobals() +{ + delete sigHandler; + delete libLoader; + delete socketMgr; + delete threadMgr; + delete handler; + delete sLog; +} + +void Application::_InitServerSocket() +{ + int r; + struct sockaddr_in dest; + ServerSocket = socket(AF_INET, SOCK_STREAM, 0) ; + setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, &ServerSocket, sizeof ServerSocket); + setNonblocking(ServerSocket); + if (ServerSocket < 0) + { + sLog->outError("Socket Creation failed. Error: %d",errno); + exit(-1); + } + + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(IntConfigs[CONFIG_INT_BIND_PORT]); + dest.sin_addr.s_addr = inet_addr(StringConfigs[CONFIG_STRING_BIND_IP].c_str()); + //Bind + r= bind(ServerSocket, (struct sockaddr*)&dest, sizeof(dest)); + if (r == -1) + { + sLog->outError("Bind Returned Error: %d", errno); + close(ServerSocket); + exit(-1); + } + + //Listen + r=listen(ServerSocket, 5); + if (r == -1) + { + sLog->outError("Listen Returned Error: %d", errno); + close(ServerSocket); + exit(-1); + } + else + sLog->outControl("[Init Server Socket] Server Socket Listening on: %s:%d",StringConfigs[CONFIG_STRING_BIND_IP].c_str(),IntConfigs[CONFIG_INT_BIND_PORT]); +} + +void* CallProcessQueue(void* obj) +{ + ((PacketHandler*)obj)->ProcessQueue(); + return NULL; +} + +void HandleInterupt(int /* p */) +{ + app->Terminate(); +} + +void Application::Terminate() +{ + handler->Terminate(); + if (threadMgr->GetThreadStatus("Queue") == THREAD_SUSPENDED) + threadMgr->ResumeThread("Queue"); + terminate = true; +} + +uint32 Application::Update() +{ + LoadLibrary(); + if (libLoader->getError()) + { + sLog->outError("Library Loader Returned Error: %s", libLoader->getError()); + return -1; + } + + if (proto.OnLoad) // Enable Library to Init its variables + proto.OnLoad(); + + outDebugParams(); + outDebugLibrary(); + _InitServerSocket(); + + sigHandler->setSignalHandler(Interupt, &HandleInterupt); + + fd_set Recv, test; + int nfds = ServerSocket+1 ,r =0; + + FD_ZERO(&Recv); + FD_SET(ServerSocket, &Recv); + + timeval selectTimeout; + selectTimeout.tv_sec = 0; + selectTimeout.tv_usec = 500000; + + int ProcessQueue = threadMgr->CreateThread("Queue", &CallProcessQueue, handler); + if (ProcessQueue == -1) + { + sLog->outError("[Recv Thread] Executing Packet Handling Queue Failed errno: %d",errno); + exit(-1); + } + + while (!terminate) + { + test = Recv; + selectTimeout.tv_sec = 1; + selectTimeout.tv_usec = 500000; + nfds = ((socketMgr->GetHighestFd() > ServerSocket) ? socketMgr->GetHighestFd() : ServerSocket) + 1; + r = select(nfds, &test, NULL, NULL, &selectTimeout); + if (r == 0) + continue; + + if (FD_ISSET(ServerSocket, &test)) + { + struct sockaddr_in peer; + unsigned int peerSize = sizeof(peer); + int newSocket = accept(ServerSocket, (sockaddr*)&peer, &peerSize); + r--; + if (newSocket == -1) + { + if (errno != EAGAIN) + sLog->outError("[Recv Thread] Accept Error: %d", errno); + continue; + } + setNonblocking(newSocket); + Socket* sock = new Socket(newSocket, peer); + socketMgr->AddSocket(sock); + sLog->outDebug("[Recv Thread] Recieved New Connection From: %s FD: %d", inet_ntoa(peer.sin_addr), sock->GetFD()); + if (proto.OnConnect) + { + //handler->AddDelayedEvent(DelayedEvent(EVENT_CONNECT, newSocket, peer.sin_addr, 100)); + handler->AddEvent(Event(EVENT_CONNECT, newSocket, peer.sin_addr)); + if (threadMgr->GetThreadStatus(ProcessQueue) == THREAD_SUSPENDED) + sLog->outDebug("[Recv Thread] Resuming Queue thread: %d Status: %s", ProcessQueue, runStatus(threadMgr->ResumeThread(ProcessQueue))); + } + FD_SET(newSocket, &Recv); + } + + if (r > 0) + for (ConnectionMgr::SocketMap::iterator sock = socketMgr->sockets.begin(); sock != socketMgr->sockets.end() && r; sock++) + if (FD_ISSET(sock->second->GetFD(), &test)) + { + BinnaryData* data = new BinnaryData(); + data->reserve(16 * IN_KILOBYTES); + int recieved = sock->second->Recieve(*data); + + if (recieved == 0) + { + sLog->outDebug("[Recv Thread] Client from %s disconnected (fd: %d)", sock->second->GetAddress(), sock->first); + socketMgr->CloseSocketByFd(sock->second->GetFD()); + FD_CLR(sock->second->GetFD(), &Recv); + if (proto.OnDisconnect) + { + handler->AddEvent(Event(EVENT_DISCONNECT, sock->first, sock->second->GetAddr().sin_addr)); + if (threadMgr->GetThreadStatus(ProcessQueue) == THREAD_SUSPENDED) + sLog->outDebug("[Recv Thread] Resuming Queue thread: %d Status: %s", ProcessQueue, runStatus(threadMgr->ResumeThread(ProcessQueue))); + } + } + else + if (recieved > 0) + { + if (proto.OnRecieve) + { + handler->AddEvent(Event(EVENT_RECIEVE, sock->first, sock->second->GetAddr().sin_addr, *data, recieved, sock->second->errnum())); + if (threadMgr->GetThreadStatus(ProcessQueue) == THREAD_SUSPENDED) + sLog->outDebug("[Recv Thread] Resuming Queue thread: %d Status: %s", ProcessQueue, runStatus(threadMgr->ResumeThread(ProcessQueue))); + } + } + else + switch (sock->second->errnum()) + { + case EBADF: + sLog->outString("[Recv Thread] sock: %d Error: EBADF", sock->second->GetFD()); + FD_CLR(sock->second->GetFD(), &Recv); + socketMgr->CloseSocketByFd(sock->second->GetFD()); + break; + case EAGAIN: + break; + default: + sLog->outError("[Recv Thread] Recv Error %d (From %s fd: %d)", sock->second->errnum(), sock->second->GetAddress(), sock->first); + } + r--; + } + socketMgr->CloseAllPendingSockets(); + } + + socketMgr->CloseAllSockets(); + close(ServerSocket); + threadMgr->JoinThead(ProcessQueue, NULL); + sLog->outControl("[Main Process] Exiting Application"); + return 1; +} diff --git a/Application/Application.h b/Application/Application.h new file mode 100644 index 0000000..c02ead0 --- /dev/null +++ b/Application/Application.h @@ -0,0 +1,137 @@ +#include "Includes.h" +#include "Defs.h" +#include "Utils.h" +#include "ThreadMgr.h" +#include "SimpleLog.h" +#include "Shared.h" +#include "SignalHandler.h" +#include "SocketMgr.h" +#include "file.h" +#include "Handler.h" +#include "ConfigMgr.h" + +#ifndef __App +#define __App + +using Files::AsciiFile ; + + +typedef void (*onConnect)(in_addr, int); +typedef void (*onRecieve)(in_addr, int, char*); +typedef void (*onSend)(char*); +typedef void (*onDisconnect)(in_addr, int); +typedef void (*onLoad)(); +typedef void (*tFunc)(void*); + +typedef std::map Options; + +struct Protocol +{ + onConnect OnConnect; + onRecieve OnRecieve; + onSend OnSend; + onDisconnect OnDisconnect; + onLoad OnLoad; +}; + +enum IntOptions +{ + CONFIG_INT_BIND_PORT, + CONFIG_INT_LOG_LEVEL, + CONFIG_INT_MAX +}; + +enum StringOptions +{ + CONFIG_STRING_BIND_IP, + CONFIG_STRING_PROTOCOL_NAME, + CONFIG_STRING_LIBRARY_PATH, + CONFIG_STRING_RECV_FUNC, + CONFIG_STRING_SEND_FUNC, + CONFIG_STRING_CONNECT_FUNC, + CONFIG_STRING_DISCONNECT_FUNC, + CONFIG_STRING_LOAD_FUNC, + CONFIG_STRING_MAX +}; + +enum BoolOptions +{ + CONFIG_BOOL_DAEMONIZE, + CONFIG_BOOL_LOG, + CONFIG_BOOL_MAX +}; + +class PacketHandler; +class SignalHandler; +class ThreadMgr; +class ConnectionMgr; + +extern SimpleLog* sLog; + +class Application +{ + public: + Application(int,char**,const char* conf); + ~Application() { FileOptions.clear(); RunOptions.clear(); sLog->outControl("Terminating Application"); _uninitGlobals(); } + bool inDebug() const { return debug; } + bool inControl() const { return control; } + + uint32 Update(); + + SignalHandler *sigHandler; + SharedLibrary *libLoader; + ConnectionMgr *socketMgr; + ThreadMgr *threadMgr; + PacketHandler *handler; + + bool LoadLibrary(); + + struct ProtocolConfig + { + const char *ProtocolName; + uint16 BindPort; + const char *BindIP; + const char *LibraryPath; + const char *InitFuncName; + const char *RecvFuncName; + const char *SendFuncName; + const char *ConnectFuncName; + const char *DisconnectFuncName; + } config; + Protocol proto; + + inline bool Exiting() const { return terminate; } + void Terminate(); + protected: + Options FileOptions; + Options RunOptions; + bool debug; + bool control; + bool daemonize; + bool libLoaded; + bool terminate; + int ServerSocket; + + bool BoolConfigs[CONFIG_BOOL_MAX]; + int IntConfigs[CONFIG_INT_MAX]; + string StringConfigs[CONFIG_STRING_MAX]; + + private: + void ParseParams(); + void _initGlobals(); + void _uninitGlobals(); + void _InitServerSocket(); + void LoadConfigs(); + + void LoadIntConfig(string ConfigName, uint32 Config, uint32 Default = 0); + void LoadStringConfig(string ConfigName, uint32 Config, string Default = ""); + void LoadBoolConfig(string ConfigName, uint32 Config, bool Default = false); + + void LoadIntRunConfig(string ConfigName, string ShortFormat, uint32 Config); + void LoadStringRunConfig(string ConfigName, string ShortFormat, uint32 Config); + void LoadBoolRunConfig(string ConfigName, string ShortFormat, uint32 Config); + + void outDebugParams() const; + void outDebugLibrary() const; +}; +#endif diff --git a/ConfigMgr/ConfigMgr.cpp b/ConfigMgr/ConfigMgr.cpp new file mode 100644 index 0000000..2ac48fa --- /dev/null +++ b/ConfigMgr/ConfigMgr.cpp @@ -0,0 +1,176 @@ +#include "ConfigMgr.h" + + +ConfigMgr::ConfigMgr(const char* conf, char* argv[], int argc) +{ + if (argc> 0) + for (int i = 1 ; i < argc ; i++) + { + string arg = string(argv[i]); + string property, value; + refTrim(arg); + if (arg.find('=') != string::npos) + { + property = arg.substr(arg.find_first_not_of('-'), arg.find('=') - arg.find_first_not_of('-')); + refTrim(property); + value = arg.substr(arg.find('=') + 1 , string::npos); + refTrim(value); + } + else + { + property = arg.substr(arg.find_first_not_of('-'), string::npos); + value = string("1"); + } + RunOptions.insert(make_pair(property, value)); + } + + if (conf) + { + AsciiFile config(conf); + if (config) + { + char buff[1024]; + string line ; + do + { + config.getline(buff, 1024); + line = buff; + if( (line.length() > 0) && + (line[0] != '#') && (line[0] != ';') && + (line.find('=') != string::npos)) + { + refTrim(line); + string property = line.substr(0, line.find('=')); + refTrim(property); + string value = line.substr(line.find('=') + 1, string::npos); + refTrim(value); + if (property.length() && value.length()) + FileOptions.insert(make_pair(property, value)); + } + } while (!config.eof()); + } + } +} + +int ConfigMgr::LoadIntConfig(string ConfigName, int Default) +{ + if (FileOptions.size() > 0) + { + if (FileOptions.find(ConfigName) != FileOptions.end()) + { + stringstream s; + int value = 0; + s.str(FileOptions[ConfigName]); + s >> value; + return value; + } + } + return Default; +} + +string ConfigMgr::LoadStringConfig(string ConfigName, string Default) +{ + if (FileOptions.size() > 0) + if (FileOptions.find(ConfigName) != FileOptions.end()) + return FileOptions[ConfigName]; + + return Default; +} + +bool ConfigMgr::LoadBoolConfig(string ConfigName, bool Default) +{ + if (FileOptions.size() > 0) + { + if (FileOptions.find(ConfigName) != FileOptions.end()) + { + stringstream s; + bool value = 0; + s.str(FileOptions[ConfigName]); + s >> value; + return value; + } + } + return Default; +} + +int ConfigMgr::LoadIntRunConfig(string ConfigName, string ShortFormat, int Default) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + { + stringstream s; + int value = 0; + s.str(RunOptions[ConfigName]); + s >> value; + return value; + } + else + if (RunOptions.find(ShortFormat) != RunOptions.end()) + { + stringstream s; + int value = 0; + s.str(RunOptions[ShortFormat]); + s >> value; + return value; + } + } + return Default; +} + +string ConfigMgr::LoadStringRunConfig(string ConfigName, string ShortFormat, string Default) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + return RunOptions[ConfigName]; + else if (RunOptions.find(ShortFormat) != RunOptions.end()) + return RunOptions[ShortFormat]; + } + return Default; +} + +bool ConfigMgr::LoadBoolRunConfig(string ConfigName, string ShortFormat, bool Default) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + { + stringstream s; + bool value = false; + s.str(RunOptions[ConfigName]); + s >> value; + return value; + } + else + if (RunOptions.find(ShortFormat) != RunOptions.end()) + { + stringstream s; + bool value = false; + s.str(RunOptions[ShortFormat]); + s >> value; + return value; + } + } + return Default; +} + +bool ConfigMgr::RunPropertyExist(string ConfigName, string ShortFormat) +{ + if (RunOptions.size() > 0) + { + if (RunOptions.find(ConfigName) != RunOptions.end()) + return true; + else if (RunOptions.find(ShortFormat) != RunOptions.end()) + return true; + } + return false; +} + +bool ConfigMgr::FilePropertyExist(string ConfigName) +{ + if (FileOptions.size() > 0) + if (FileOptions.find(ConfigName) != RunOptions.end()) + return true; + return false; +} diff --git a/ConfigMgr/ConfigMgr.h b/ConfigMgr/ConfigMgr.h new file mode 100644 index 0000000..b398668 --- /dev/null +++ b/ConfigMgr/ConfigMgr.h @@ -0,0 +1,36 @@ +#include "Includes.h" +#include "Utils.h" +#include "DataArrays/file.h" + +using std::string; +using std::map; +using std::make_pair; +using std::stringstream; +using Files::AsciiFile; + +#ifndef __ConfigMgr +#define __ConfigMgr + +class ConfigMgr +{ + public: + typedef std::map Options; + ConfigMgr(const char* file, char* argv[], int argc); + ~ConfigMgr() { } + + int LoadIntConfig(string ConfigName, int Default = 0); + string LoadStringConfig(string ConfigName, string Default = ""); + bool LoadBoolConfig(string ConfigName, bool Default = false); + + int LoadIntRunConfig(string ConfigName, string ShortFormat, int Default = 0); + string LoadStringRunConfig(string ConfigName, string ShortFormat, string Default = ""); + bool LoadBoolRunConfig(string ConfigName, string ShortFormat, bool Default = false); + + bool RunPropertyExist(string ConfigName, string ShortFormat); + bool FilePropertyExist(string ConfigName); + + Options FileOptions; + Options RunOptions; +}; + +#endif // __ConfigMgr diff --git a/DataArrays/binData.cpp b/DataArrays/binData.cpp new file mode 100644 index 0000000..53379bd --- /dev/null +++ b/DataArrays/binData.cpp @@ -0,0 +1,426 @@ +#include "binData.h" + +/* */ +/* Alocators / dealocators */ +/* */ + +void BinnaryData::reserve(size_t len) +{ + if (maxLength == len) + return; + if (maxLength > len) + { + memset(data + len, 0, maxLength -len); + return; + } + if (maxLength < len) + { + byte *buffer = new byte[len]; + memset(buffer, 0, len); + if (usedLength) + { + memcpy(buffer,data,usedLength); + pget = buffer + (pget-data); + pput = buffer + (pput-data); + delete data; + } + maxLength = len; + data = buffer; + if (!pget || pget-data < 0 || (pget-data) > maxLength)pget = data; + if (!pput || pput-data < 0 || (pput-data) > maxLength)pput = data; + } +} + +void BinnaryData::clear() +{ + if (usedLength) + { + memset(data, 0, usedLength); + delete data; + } + _init(); +} + +/* */ +/* IO pointers funcs */ +/* */ + + +void BinnaryData::seekg(size_t to = 0, IOposition pos = beg) +{ + switch (pos) + { + case beg: pget = data + (to > maxLength ? usedLength : to);break; + case end: pget = data + (to > usedLength ? usedLength : usedLength - to);break; + } +} +void BinnaryData::seekg(IOposition pos) +{ + switch (pos) + { + case beg: pget = data ;break; + case end: pget = data + usedLength ;break; + } +} +void BinnaryData::seekg(int by) +{ + pget = ((pget-data)-by > 0 ? pget-by : data+usedLength+((pget-data)-by)); +} + + +void BinnaryData::seekp(size_t to = 0, IOposition pos = beg) +{ + switch (pos) + { + case beg: + pput = data + ( to > maxLength ? usedLength : to); + break; + case end: + pput = data + (to > usedLength ? usedLength : usedLength - to); + break; + } +} + +void BinnaryData::seekp(IOposition pos) +{ + switch (pos) + { + case beg: + pput = data; + break; + case end: + pput = data + usedLength; + break; + } +} + +void BinnaryData::seekp(int by) +{ + pput = ((pput-data)-by > 0 ? pput-by : data+usedLength+((pput-data)-by)); +} + +template +void BinnaryData::skip() +{ + pget = ((pget-data)-sizeof(T) > 0 ? pget-sizeof(T) : data+usedLength+((pget-data)-sizeof(T))); +} + +template +void BinnaryData::read(T& dat) +{ + memcpy(&dat, pget, sizeof(T)); + pget += sizeof(T); +} + +template +void BinnaryData::write(T& dat) +{ + if ((pput - data + sizeof(T)) > usedLength) + grow((pput - data + sizeof(T)) - usedLength); + memcpy(pput, &dat, sizeof(T)); + pput += sizeof(T); + usedLength += sizeof(T); +} + +/* */ +/* Output public member functions */ +/* */ + + +size_t BinnaryData::read(void *dest, size_t num= maxpos) const +{ + if (usedLength == 0 || !dest) + return 0 ; + memcpy(dest, data, (usedLength > num ? num : usedLength)); + return (usedLength>num?num:usedLength); +} + +size_t BinnaryData::readsome(void *dest, size_t num = maxpos) +{ + assert(pget); + if (usedLength == 0 || !dest) + return 0; + memcpy(dest, pget, (usedLength - (pget - data) > num ? num : usedLength - (pget - data))); + pget = pget + (usedLength - (pget - data) > num ? num : usedLength - (pget - data)); + return (usedLength - (pget - data) > num ? num : usedLength - (pget - data)); +} + +/* */ +/* Input public member functions */ +/* */ + +void BinnaryData::write(const void *src, size_t num) +{ + if (num == 0 || !src) + return; + if ((num + usedLength) > maxLength) + grow(num); + memcpy(pput, src, num); + usedLength += num ; + pput += num ; +} + +void BinnaryData::append(const void *src, size_t num) +{ + if (num == 0 || !src) + return; + if ((num + usedLength) > maxLength) + grow(num); + memcpy(data + usedLength, src, num); + usedLength += num ; +} + + +/* */ +/* Subscript Overload */ +/* */ + +byte BinnaryData::operator [](size_t pos)const +{ + if (pos > maxLength) + pos = maxLength; + return byte(*(data + pos)); +} + + + +/* */ +/* Inserter Overloads (normal) */ +/* */ + + +BinnaryData& BinnaryData::operator << (byte dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (char dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (char* dat) +{ + size_t len = strlen(dat); // -1 'cause character + write(dat, len); + return *this; +} + + +BinnaryData& BinnaryData::operator << (short dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (unsigned short dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (int dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (unsigned int dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (long dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (unsigned long dat) +{ + write(dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (BinnaryData dat) +{ + write(dat.getBuffer(), dat); + return *this; +} + +BinnaryData& BinnaryData::operator << (std::string dat) +{ + write(dat.c_str(), dat.length()); + return *this; +} + + +BinnaryData& BinnaryData::operator << (std::stringstream dat) +{ + write(dat.str().c_str(), dat.str().length()); + return *this; +} + +/* */ +/* Inserter Overloads (constants) */ +/* */ + + +BinnaryData& BinnaryData::operator << (const char* dat) +{ + size_t len = strlen(dat); // -1 'cause character + write(const_cast(dat),len); + return *this; +} + +/* */ +/* Extractor Overloads */ +/* */ + + + +BinnaryData& BinnaryData::operator >> (byte& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (char& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (short& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (unsigned short& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (int& dat) +{ + read(dat); + return *this; +} +BinnaryData& BinnaryData::operator >> (unsigned int& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (long& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (unsigned long& dat) +{ + read(dat); + return *this; +} + +BinnaryData& BinnaryData::operator >> (std::string& dat) +{ + size_t pos = _find(' '); + size_t endline = _find('\n'); + if (*(pget + endline) == '\r') + endline--; + if (pos > endline) + pos = endline; + char stream[pos + 1]; + memset(stream, 0, pos+1); + readsome(stream ,pos); + pget++; + dat = string(stream); + return *this; +} + +string BinnaryData::getline() +{ + size_t pos = _find('\n'); + if (*(pget + pos) == '\r') + pos--; + char stream[pos+1]; + memset(stream, 0, pos+1); + readsome(stream ,pos); + if (*pget == '\r') + pget++; + if (*pget == '\n') + pget++; + return string(stream); +} + +/* */ +/* Searching / Locating / Finding */ +/* */ + +size_t BinnaryData::find(byte ch) +{ + for (size_t i = 0;i 0) + n << '\n'; + else + n << ' '; + } + } + return n.str(); +} diff --git a/DataArrays/binData.h b/DataArrays/binData.h new file mode 100644 index 0000000..a62e167 --- /dev/null +++ b/DataArrays/binData.h @@ -0,0 +1,128 @@ +#include // string.h / cstring for memcpy , memset +#include +#include +#include +#include +#include + +using namespace std; + +#ifndef __BinnaryData +#define __BinnaryData + +typedef unsigned char byte ; +typedef unsigned short uint16 ; +typedef unsigned int uint32 ; +typedef unsigned long uint64 ; + +#define BinData BinnaryData + +enum IOposition +{ + beg, + end +}; + + +class BinnaryData +{ + public: + BinnaryData() { _init(); } + BinnaryData(void *src, size_t num) { _init(); write(src,num); } + ~BinnaryData() { if ((usedLength || maxLength) && data) delete data; } + + size_t read(void *dest, size_t num)const; + size_t readsome(void *dest, size_t num); + void write(const void *src, size_t num); + void append(const void *src, size_t num); + + byte get() { byte g = *pget; (pget-data) == usedLength ? pget= data+usedLength : pget+=1 ; return g; } + void unget() { (pget-data) > 0 ? pget-=1 : pget= data+usedLength ; } + void put(byte dat) { write(dat); } + + byte* getBuffer() const { return data; } + byte* getBufferPut() const { return pput; } + + size_t tellg() const { return (data-pget); } + void seekg(size_t to, IOposition pos); + void seekg(IOposition pos); + void seekg(int by); + + size_t teelp() const { return (data-pput); } + void seekp(size_t to, IOposition pos); + void seekp(IOposition pos); + void seekp(int by); + + byte operator [](size_t) const; + operator int() const { return usedLength; } + operator size_t() const { return usedLength; } + operator long int() const { return usedLength; } + operator char*() const { return (char*)(data); } + operator byte*() const { return (data); } + operator void*() const { return data; } + operator bool() const { return (usedLength > 0 ? true : false); } + + BinnaryData& operator << (byte); + BinnaryData& operator << (char); + BinnaryData& operator << (char*); + BinnaryData& operator << (const char*); + BinnaryData& operator << (short); + BinnaryData& operator << (unsigned short); + BinnaryData& operator << (int); + BinnaryData& operator << (unsigned int); + BinnaryData& operator << (long); + BinnaryData& operator << (unsigned long); + BinnaryData& operator << (BinnaryData); + BinnaryData& operator << (std::string); + BinnaryData& operator << (std::stringstream); + + BinnaryData& operator >> (byte&) ; + BinnaryData& operator >> (char &); + BinnaryData& operator >> (int&); ; + BinnaryData& operator >> (unsigned int&); + BinnaryData& operator >> (short&); + BinnaryData& operator >> (unsigned short&); + BinnaryData& operator >> (long&); + BinnaryData& operator >> (unsigned long&); + BinnaryData& operator >> (std::string&); + + string getline(); + + template + void skip(); + + template + void write(T& data); + + template + void read(T& data); + + string TextLike(); + string HexLike(); + + size_t find(byte); + size_t _find(byte); + size_t find(byte*, size_t); + size_t locate(byte ch); + + void setLength(size_t len) { usedLength = len; } + + void clear(); + size_t size() const { return usedLength; } + size_t capacity() const { return maxLength; } + void reserve(size_t); + void grow(size_t by) { reserve(maxLength + by); } + + static const size_t maxpos = -1; + + private: + byte *data; + size_t usedLength; + size_t maxLength; + byte *pget; + byte *pput; + + void _init(){data= NULL ; pget = NULL ; pput = NULL; usedLength = 0 ; maxLength = 0;} +}; + +#endif diff --git a/DataArrays/file.cpp b/DataArrays/file.cpp new file mode 100644 index 0000000..6a0ac35 --- /dev/null +++ b/DataArrays/file.cpp @@ -0,0 +1,102 @@ +#include "file.h" + +namespace Files{ + +void AsciiFile::_openFile(const char* fileName) +{ + if ((FileName != string(fileName)) && (string(fileName).length()> 0 )) + { + open(fileName); + FileName = string(fileName); + } + if (!is_open()) + open(FileName.c_str()); +} + + +void AsciiFile::_readFile() +{ + if (!is_open()) + return; + if (length != getLength()) + length = getLength(); + if (!length) + return; + char* buffer = new char[length+1]; + memset(buffer,0,length+1); + read(buffer,length); + content = string(buffer); +} + +size_t AsciiFile::getLength() +{ + if (!is_open()) + return 0; + seekg(0,ios_base::end); + long len = tellg(); + seekg(0,ios_base::beg); + return len ; +} + +void AsciiFile::SaveToFile() +{ + if (!is_open()) + return; + seekp(ios_base::beg); + write(content.c_str(),content.length()); +} + +void BinFile::_openFile(const char* fileName) +{ + if ((FileName.compare(fileName) != 0) && (strlen(fileName)> 0 )) + { + open(fileName); + FileName = string(fileName); + } + if (!is_open()) + open(FileName.c_str()); +} + + +void BinFile::_readFile() +{ + if (!is_open()) + return; + if (length != getLength()) + length = getLength(); + if (!length) + return; + content.clear(); + content.reserve(length); + read(content,length); +} + +size_t BinFile::getLength() +{ + if (!is_open()) + return 0; + seekg(0,ios_base::end); + long len = tellg(); + seekg(0,ios_base::beg); + return len ; +} + +void BinFile::SaveToFile() +{ + if (!is_open()) + return; + seekp(ios_base::beg); + write(content, content); +} + +void BinFile::SaveToFile(const char* file) +{ + _openFile(file); + printf("\nBinFile::SaveToFile file: %s is open: %s\n\n", file, is_open()? "true": "false"); + if (!is_open()) + return; + seekp(ios_base::beg); + write(content, content); +} + +} diff --git a/DataArrays/file.h b/DataArrays/file.h new file mode 100644 index 0000000..f98a8f2 --- /dev/null +++ b/DataArrays/file.h @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +#include "binData.h" + +#ifndef __Files +#define __Files + + +#define __Debug + +#ifdef __Debug +#include +using std::cout ; +using std::endl ; +#endif + + + +namespace Files { + +using namespace std; + +class AsciiFile : public std::fstream +{ + public: + AsciiFile() : length(0), content(""), FileName("") { } + AsciiFile(const char* fileName) : length(0), content("") {_openFile(fileName);} + AsciiFile(string fileName) : length(0), content("") { _openFile(fileName.c_str()); } + ~AsciiFile() { if(is_open())close(); } + + char* readFile(string File) { _openFile(File.c_str()); _readFile(); return const_cast(content.c_str()); } + char* readFile(const char* File) { _openFile(File); _readFile(); return const_cast(content.c_str()); } + char* readFile() { return const_cast(content.c_str()); } + string sreadFile(string File) { _openFile(File.c_str()); _readFile(); return content; } + string sreadFile(const char* File) { _openFile(File); _readFile(); return content; } + string sreadFile() { return content ; } + + void writeFile(string Content) { content = Content; } + void writeFile(char* Content) { content = string(Content); } + + void append(char* Content) { content += string(Content); } + void append(string Content) { content += Content; } + + string getFileName() { return FileName; } + + size_t getLength(); + + size_t size() const { return length; } + + char* toCharArray() const { return const_cast(content.c_str()); } + string toString() const { return content ;} ; + + operator string() const { return content ;} + operator char*() const { return const_cast(content.c_str()); } + operator bool() { return (is_open() ); } + + + friend std::ostream& operator <<(std::ostream &os,const AsciiFile &obj){os<Update(getMsTimeDiffToNow(it->updated)); + if (it->Execute()) + queue.push(*it); + } + + for (DelayedEventQueue::iterator it = delayedQueue.begin(); it != delayedQueue.end(); it++) + if (it->Execute()) + { + delayedQueue.erase(it); + it = delayedQueue.begin(); + if (!delayedQueue.size()) + break; + } +} + +void PacketHandler::Terminate() +{ + sLog->outControl(); + sLog->outControl("[PacketHandler] Droping %d delayed events.", delayedQueue.size()); + delayedQueue.clear(); + sLog->outControl("[PacketHandler] Droping %d immediate events.", queue.size()); + while (queue.size()) + queue.pop(); + process = false; +} + +void PacketHandler::ProcessQueue() +{ + assert(app); + sigHandler = new SignalHandler(); + sigHandler->setSignalHandler(Continue, SigContHandler); + sLog->outControl("[PacketHandler] Process Queue initialization"); + sigset_t suspendSig; + sigemptyset(&suspendSig); + int sig = SIGCONT; + timeval workBegan; + gettimeofday(&workBegan, 0); + while (process) + { + UpdateDelayed(); + gettimeofday(&workBegan, 0); + if (!queue.size() && !delayedQueue.size()) + { + //sLog->outDebug("Process Queue goes to sleep (until data arrives)"); + sigaddset(&suspendSig, SIGCONT); + sigaddset(&suspendSig, SIGINT); + sigaddset(&suspendSig, SIGTERM); + app->threadMgr->SetThreadStatus(GetThisThread(), THREAD_SUSPENDED); + sigwait(&suspendSig, &sig); + app->threadMgr->SetThreadStatus(GetThisThread(), THREAD_ACTIVE); + //sLog->outDebug("Process Queue was suspended %lu milliseconds", getMsTimeDiffToNow(workBegan)); + } + + if (queue.size()) + { + Event& event = queue.front(); + switch (event.EventType) + { + case EVENT_CONNECT: + if (app->proto.OnConnect) + app->proto.OnConnect(event.address, event.fd); + break; + case EVENT_RECIEVE: + if (app->proto.OnRecieve) + app->proto.OnRecieve(event.address, event.fd, event.data); + delete &event.data; + break; + case EVENT_SEND: + break; + case EVENT_DISCONNECT: + if (app->proto.OnDisconnect) + app->proto.OnDisconnect(event.address, event.fd); + break; + } + //sLog->outDebug("Process Queue Update after diff: %lu milliseconds", getMsTimeDiffToNow(workBegan)); + queue.pop(); + } + else + if (delayedQueue.size()) + msleep(500); + } + sLog->outControl("[PacketHandler] Process Queue exit"); + ThreadMgr::Exit(NULL); +} diff --git a/Handling/Handler.h b/Handling/Handler.h new file mode 100644 index 0000000..dbd80bb --- /dev/null +++ b/Handling/Handler.h @@ -0,0 +1,90 @@ +#ifndef __PacketHandler +#define __PacketHandler + +#include "Includes.h" + +#include "SimpleLog.h" +#include "file.h" +#include "Defs.h" +#include "Application.h" + +using namespace Files; + +enum Events +{ + EVENT_CONNECT = 0, + EVENT_RECIEVE, + EVENT_SEND, + EVENT_DISCONNECT +}; + +struct Event +{ + Event(byte e, int f, in_addr addr, BinnaryData& dat = *(new BinnaryData()), int recv = 0, int err = 0): + EventType(e), fd(f), address(addr), data(dat), recieved(recv), errorcode(err) + { + } + byte EventType; + int fd; + in_addr address; + BinnaryData& data; + int recieved; + int errorcode; +}; + +struct DelayedEvent : Event +{ + DelayedEvent(byte e, int f, in_addr addr, uint64 delay, BinnaryData& dat = *(new BinnaryData()), int recv = 0, int err = 0): + Event(e, f, addr, dat, recv, err), + msDelay(delay) + { + updated.tv_sec = 0; + updated.tv_usec = 0; + gettimeofday(&updated, 0); + } + + DelayedEvent(byte e, int f, in_addr addr, BinnaryData& dat = *(new BinnaryData()), int recv = 0, int err = 0): + Event(e, f, addr, dat, recv, err), + msDelay(1000) + { + updated.tv_sec = 0; + updated.tv_usec = 0; + gettimeofday(&updated, 0); + } + + uint64 msDelay; + timeval updated; + + bool Execute() const { return !msDelay; } + void Update(uint64 diff) { msDelay -= msDelay > diff? diff : msDelay; gettimeofday(&updated, 0); } + void SetDelay(uint64 delay) { msDelay = delay; gettimeofday(&updated, 0); } +}; + +class Application; +extern SimpleLog* sLog; +extern Application* app; + +class PacketHandler +{ + public: + typedef std::queue EventQueue; + typedef std::list DelayedEventQueue; + PacketHandler(); + ~PacketHandler(); + + void AddEvent(Event event); + void AddDelayedEvent(DelayedEvent event); + void ProcessQueue(); + void UpdateDelayed(); + void Terminate(); + + private: + SignalHandler* sigHandler; + + bool process; + + EventQueue queue; + DelayedEventQueue delayedQueue; +}; + +#endif diff --git a/OLD_Makefiles/Protocol/FTP/makefile b/OLD_Makefiles/Protocol/FTP/makefile new file mode 100644 index 0000000..2415680 --- /dev/null +++ b/OLD_Makefiles/Protocol/FTP/makefile @@ -0,0 +1,4 @@ +include ../makefile + +all: + @$(blue);$(bold);echo "Making libftp.so";g++ $(SyntaxFlags) $(SharedFlags) $(Flags) -o libftp.so Base.cpp;$(normal) diff --git a/OLD_Makefiles/Protocol/HTTP/makefile b/OLD_Makefiles/Protocol/HTTP/makefile new file mode 100644 index 0000000..9cd7ecc --- /dev/null +++ b/OLD_Makefiles/Protocol/HTTP/makefile @@ -0,0 +1,4 @@ +include ../makefile + +all: + @$(blue);$(bold);echo "Making libhttp.so";g++ $(SyntaxFlags) $(Flags) $(SharedFlags) -o libhttp.so Base.cpp;$(normal) diff --git a/OLD_Makefiles/Protocol/SMTP/makefile b/OLD_Makefiles/Protocol/SMTP/makefile new file mode 100644 index 0000000..8c036f2 --- /dev/null +++ b/OLD_Makefiles/Protocol/SMTP/makefile @@ -0,0 +1,4 @@ +include ../makefile + +all: + @$(blue);$(bold);echo "Making libsmtp.so";g++ $(SyntaxFlags) $(SharedFlags) $(Flags) -o libsmtp.so Base.cpp;$(normal) diff --git a/OLD_Makefiles/Protocol/libdump/makefile b/OLD_Makefiles/Protocol/libdump/makefile new file mode 100644 index 0000000..cf42ef7 --- /dev/null +++ b/OLD_Makefiles/Protocol/libdump/makefile @@ -0,0 +1,6 @@ +SharedFlags= -shared -fPIC +SyntaxFlags= -W -Wall + +all: + + g++ $(SyntaxFlags) $(SharedFlags) -o libdump.so libdump.cpp diff --git a/OLD_Makefiles/Protocol/makefile b/OLD_Makefiles/Protocol/makefile new file mode 100644 index 0000000..38ac14e --- /dev/null +++ b/OLD_Makefiles/Protocol/makefile @@ -0,0 +1,26 @@ +SharedFlags= -shared -fPIC +SyntaxFlags= -W -Wall + +SourceRootDir= /home/ntx/Plocha/MultiServer +ApplicationInclude = $(SourceRootDir)/Application +DataStructInclude = $(SourceRootDir)/DataArrays +HandlingInclude = $(SourceRootDir)/Handling +SignalInclude = $(SourceRootDir)/Signal +SharedInclude = $(SourceRootDir)/Shared +SimpleLogInclude = $(SourceRootDir)/SimpleLog +SocketsInclude = $(SourceRootDir)/Sockets +ThreadsInclude = $(SourceRootDir)/Threads +ProtocolInclude = $(SourceRootDir)/Protocol +ConfigMgrInclude = $(SourceRootDir)/ConfigMgr + +IncludeDirs= -I $(SourceRootDir) -I $(ApplicationInclude) -I $(DataStructInclude) -I $(HandlingInclude) -I $(SignalInclude) -I $(SharedInclude) -I $(SimpleLogInclude) -I $(SocketsInclude) -I $(ThreadsInclude) -I $(ProtocolInclude) -I $(ConfigMgrInclude) + +Flags += $(IncludeDirs) + +black= tput setaf 0 +red= tput setaf 1 +green= tput setaf 2 +orange= tput setaf 3 +blue= tput setaf 4 +bold= tput bold +normal= tput sgr0 diff --git a/OLD_Makefiles/README.TXT b/OLD_Makefiles/README.TXT new file mode 100644 index 0000000..e88da81 --- /dev/null +++ b/OLD_Makefiles/README.TXT @@ -0,0 +1,2 @@ +This directory contains Old makefiles, +if you want to use them, just copy entire directory to Source Directory diff --git a/OLD_Makefiles/makefile b/OLD_Makefiles/makefile new file mode 100755 index 0000000..363a847 --- /dev/null +++ b/OLD_Makefiles/makefile @@ -0,0 +1,116 @@ +CC=@g++ +Flags=-W -Wall -O2 -ldl -rdynamic -pthread -g +BaseDir=./ +BuildDir=./build/ +Additions= -ldl -rdynamic $(BaseDir)Shared/Shared.h +OutputFileName= server +Output=-o $(BaseDir)$(OutputFileName) + + +SourceRootDir= /home/ntx/Plocha/MultiServer +ApplicationInclude = $(SourceRootDir)/Application +DataStructInclude = $(SourceRootDir)/DataArrays +HandlingInclude = $(SourceRootDir)/Handling +SignalInclude = $(SourceRootDir)/Signal +SharedInclude = $(SourceRootDir)/Shared +SimpleLogInclude = $(SourceRootDir)/SimpleLog +SocketsInclude = $(SourceRootDir)/Sockets +ThreadsInclude = $(SourceRootDir)/Threads +ConfigMgrInclude = $(SourceRootDir)/ConfigMgr + +IncludeDirs= -I $(SourceRootDir) -I $(ApplicationInclude) -I $(DataStructInclude) -I $(HandlingInclude) -I $(SignalInclude) -I $(SharedInclude) -I $(SimpleLogInclude) -I $(SocketsInclude) -I $(ThreadsInclude) -I $(ConfigMgrInclude) + +Flags += $(IncludeDirs) + +Objs= build/Utils.o build/binData.o build/file.o build/SimpleLog.o -ldl build/Shared.o build/SignalHandler.o\ + build/Socket.o build/SocketMgr.o build/ThreadMgr.o build/ConfigMgr.o build/Handler.o build/Application.o build/main.o + +ObjectOut=-o $@ + + +black= tput setaf 0 +red= tput setaf 1 +green= tput setaf 2 +orange= tput setaf 3 +blue= tput setaf 4 +bold= tput bold +normal= tput sgr0 + +all: $(Objs) + @cd $(BuildDir);make; + +install: all HTTP SMTP FTP + @cp ./server ./Server/ + +HTTP: + @cd ./Protocol/HTTP/;make; + @cp ./Protocol/HTTP/*.so ./Server/ + +SMTP: + @cd ./Protocol/SMTP/;make; + @cp ./Protocol/SMTP/*.so ./Server/ + +FTP: + @cd ./Protocol/FTP/;make; + @cp ./Protocol/FTP/*.so ./Server/ + +clean: + @$(red);$(bold);echo "[ 1 / 2 ] Cleaning Root Directory";$(normal) + @rm -rf ./*.o + @rm -rf ./$(OutputFileName) + @rm -rf ./*.out + @cd $(BuildDir);make clean; + +$(Objs): $(BaseDir)Includes.h $(BaseDir)Defs.h + +build/Utils.o: Utils.cpp Utils.h + @$(blue);$(bold);echo "Building Utilities";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Utils.cpp + +build/binData.o: DataArrays/binData.cpp DataArrays/binData.h + @$(blue);$(bold);echo "Building Binary Data Class";$(normal) + $(CC) $(Flags) $(ObjectOut) -c DataArrays/binData.cpp + +build/file.o: $(BuildDir)binData.o DataArrays/file.cpp DataArrays/file.h + @$(blue);$(bold);echo "Building File Class";$(normal) + $(CC) $(Flags) $(ObjectOut) -c DataArrays/file.cpp + +build/SimpleLog.o: SimpleLog/SimpleLog.cpp SimpleLog/SimpleLog.h + @$(blue);$(bold);echo "Building Loging";$(normal) + $(CC) $(Flags) $(ObjectOut) -pthread -c SimpleLog/SimpleLog.cpp + +build/Shared.o: Shared/Shared.cpp Shared/Shared.h + @$(blue);$(bold);echo "Building Shared";$(normal) + $(CC) $(Flags) $(ObjectOut) -ldl -rdynamic -c Shared/Shared.cpp + +build/SignalHandler.o: Signal/SignalHandler.cpp Signal/SignalHandler.h + @$(blue);$(bold);echo "Building Signal Handler";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Signal/SignalHandler.cpp + +build/Socket.o: Sockets/Socket.cpp Sockets/Socket.h + @$(blue);$(bold);echo "Building Sockets";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Sockets/Socket.cpp + +build/SocketMgr.o: $(BuildDir)Socket.o Sockets/SocketMgr.cpp Sockets/SocketMgr.h + @$(blue);$(bold);echo "Building Socket Manager";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Sockets/SocketMgr.cpp + +build/ThreadMgr.o: Threads/ThreadMgr.cpp Threads/ThreadMgr.h + @$(blue);$(bold);echo "Building Thread Manager";$(normal) + $(CC) $(Flags) $(ObjectOut) -pthread -c Threads/ThreadMgr.cpp + +build/Handler.o: Handling/Handler.cpp Handling/Handler.h + @$(blue);$(bold);echo "Building Data Handler";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Handling/Handler.cpp + +build/Application.o: Application/Application.cpp Application/Application.h + @$(blue);$(bold);echo "Building Application";$(normal) + $(CC) $(Flags) $(ObjectOut) -c Application/Application.cpp + +build/ConfigMgr.o: ConfigMgr/ConfigMgr.cpp ConfigMgr/ConfigMgr.h + @$(blue);$(bold);echo "Building Config Manager";$(normal) + $(CC) $(Flags) $(ObjectOut) -c ConfigMgr/ConfigMgr.cpp + +build/main.o: main.cpp + @$(blue);$(bold);echo "Building Main Function";$(normal) + $(CC) $(Flags) $(ObjectOut) -c main.cpp diff --git a/Protocol/CMakeLists.txt b/Protocol/CMakeLists.txt new file mode 100644 index 0000000..e33d593 --- /dev/null +++ b/Protocol/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(FTP) +add_subdirectory(HTTP) +add_subdirectory(SMTP) +add_subdirectory(libdump) diff --git a/Protocol/FTP/Adds.cpp b/Protocol/FTP/Adds.cpp new file mode 100644 index 0000000..cc5297a --- /dev/null +++ b/Protocol/FTP/Adds.cpp @@ -0,0 +1,30 @@ +#include "Adds.h" +#include + + +string lower(string in) +{ + string out = in; + for (uint32 i = 0; i< in.length();i++) + if (out[i] >= 'A' && out[i] <= 'Z') + out[i] = out[i] + 32; + return out; +} + +string trim(string in) +{ + size_t pos = in.find_first_not_of(" \r\n\t"); + in.erase(0, pos ); + pos = in.find_last_not_of(" \r\n\t"); + if (pos == string::npos) + return in; + in.erase(pos + 1, string::npos); + return in; +} + +int FileExists(string file) +{ + struct stat buffer; + int ret = stat(file.c_str(), &buffer); + return ret == 0 ? 0 : errno; +} diff --git a/Protocol/FTP/Adds.h b/Protocol/FTP/Adds.h new file mode 100644 index 0000000..92982fe --- /dev/null +++ b/Protocol/FTP/Adds.h @@ -0,0 +1,10 @@ +#include "Includes.cpp" + + +#ifndef __Adds +#define __Adds + + +int FileExists(string file); + +#endif // __Adds diff --git a/Protocol/FTP/Base.cpp b/Protocol/FTP/Base.cpp new file mode 100755 index 0000000..9a827fb --- /dev/null +++ b/Protocol/FTP/Base.cpp @@ -0,0 +1,439 @@ +#include "Base.h" + +struct MapStringComparsionStruct +{ + bool operator() (const string a, const string b) const + { + return a.compare(b) < 0; + } +}; + +std::map commandTable; + +void InitMessages(); +void InitCommandTable(); +void LoadConfigs(); + +void Init() +{ + configMgr = new ConfigMgr("ftp.conf", NULL, 0); + protoLog = new SimpleLog(boolConfigs[CONFIG_BOOL_CONTROL], boolConfigs[CONFIG_BOOL_DEBUG], "Protocol.log"); + LoadConfigs(); + InitMessages(); + InitCommandTable(); +} + +void InitMessages() +{ + // Connect + responseCodeMessage.insert(make_pair(220, "Welcome to Ikaros SMTP Server")); + responseCodeMessage.insert(make_pair(231, "User logged out; service terminated.")); + responseCodeMessage.insert(make_pair(421, "Service not avaliable, closing control channel")); + // Not Implemented + responseCodeMessage.insert(make_pair(500, "Syntax error, command uncategorized")); + responseCodeMessage.insert(make_pair(501, "Syntax error in parameters or arguments.")); + responseCodeMessage.insert(make_pair(502, "Not Implemented")); + responseCodeMessage.insert(make_pair(530, "Not Logged In")); + responseCodeMessage.insert(make_pair(550, "Requested Action not taken")); + // Quit + responseCodeMessage.insert(make_pair(221, "Bye")); + + // Login + responseCodeMessage.insert(make_pair(331, "User name okay, need password.")); + responseCodeMessage.insert(make_pair(230, "User logged in, proceed.")); + + // commands + responseCodeMessage.insert(make_pair(200, "Ok Command successfull.")); + responseCodeMessage.insert(make_pair(227, "Entering Passive mode.")); + responseCodeMessage.insert(make_pair(250, "Requested file action okay, completed.")); + responseCodeMessage.insert(make_pair(257, "\"PATH\" created.")); + + responseCodeMessage.insert(make_pair(150, "File status okay; about to open data connection.")); + responseCodeMessage.insert(make_pair(226, "Closing data connection. Requested file action successful.")); + responseCodeMessage.insert(make_pair(425, "Can't open data connection.")); + responseCodeMessage.insert(make_pair(426, "Connection closed; transfer aborted.")); + + responseCodeMessage.insert(make_pair(450, "Requested file action not taken.")); + responseCodeMessage.insert(make_pair(550, "Requested action not taken.")); + protoLog->outControl("Initialised %u Reponse Code Messages", responseCodeMessage.size()); +} + +void InitCommandTable() +{ + commandTable.insert(make_pair("user", FTP_LOGIN_USER)); + commandTable.insert(make_pair("pass", FTP_LOGIN_PASS)); + + commandTable.insert(make_pair("cwd", FTP_CHANGE_WORKING_DIRECTORY)); + commandTable.insert(make_pair("pwd", FTP_PRINT_WORKING_DIRECTORY)); + commandTable.insert(make_pair("cdup", FTP_CHANGE_WORKING_DIRECTORY_TO_PARENT)); + commandTable.insert(make_pair("mkd", FTP_MAKE_DIR)); + commandTable.insert(make_pair("rmd", FTP_REMOVE_DIR)); + + commandTable.insert(make_pair("port", FTP_SESSION_PORT)); + commandTable.insert(make_pair("pasv", FTP_SESSION_PASSIVE)); + commandTable.insert(make_pair("type", FTP_TRANSFER_TYPE)); + + commandTable.insert(make_pair("quit", FTP_QUIT)); + commandTable.insert(make_pair("help", FTP_HELP)); + commandTable.insert(make_pair("noop", FTP_NOOP)); + commandTable.insert(make_pair("syst", FTP_SYST)); + + commandTable.insert(make_pair("stor", FTP_STORAGE_STORE)); + commandTable.insert(make_pair("retr", FTP_STORAGE_RETRIEVE)); + commandTable.insert(make_pair("dele", FTP_STORAGE_DELETE)); + commandTable.insert(make_pair("list", FTP_LIST)); + protoLog->outControl("Initialised %u Command definitions", commandTable.size()); +} + +void LoadConfigs() +{ + stringConfigs[CONFIG_STRING_GREETINGS] = configMgr->LoadStringConfig("Greetings", "Welcome to FTP Server"); + + boolConfigs[CONFIG_BOOL_DEBUG] = configMgr->LoadBoolConfig("Debug", true); + boolConfigs[CONFIG_BOOL_CONTROL] = configMgr->LoadBoolConfig("Control", true); + + intConfigs[CONFIG_INT_MAX_DATA_SEGMENT_SIZE] = configMgr->LoadIntConfig("MaxSegmentSize", 40000); + intConfigs[CONFIG_INT_SEND_ERROR_WAIT_TIME] = configMgr->LoadIntConfig("SendErrorWaitTime", 20); + intConfigs[CONFIG_INT_SEND_WAIT_TIME] = configMgr->LoadIntConfig("SendWaitTime", 0); + + intConfigs[CONFIG_INT_RECV_ERROR_WAIT_TIME] = configMgr->LoadIntConfig("RecvErrorWaitTime", 20); + intConfigs[CONFIG_INT_RECV_WAIT_TIME] = configMgr->LoadIntConfig("RecvWaitTime", 0); + + protoLog->outDebug("CONFIG_STRING_GREETINGS= '%s'", stringConfigs[CONFIG_STRING_GREETINGS].c_str()); + protoLog->outDebug("CONFIG_INT_MAX_DATA_SEGMENT_SIZE= %d", intConfigs[CONFIG_INT_MAX_DATA_SEGMENT_SIZE]); + protoLog->outDebug("CONFIG_INT_SEND_WAIT_TIME= %d", intConfigs[CONFIG_INT_SEND_WAIT_TIME]); + protoLog->outDebug("CONFIG_INT_SEND_ERROR_WAIT_TIME= %d", intConfigs[CONFIG_INT_SEND_ERROR_WAIT_TIME]); + protoLog->outDebug("CONFIG_INT_RECV_WAIT_TIME= %d", intConfigs[CONFIG_INT_RECV_WAIT_TIME]); + protoLog->outDebug("CONFIG_INT_RECV_ERROR_WAIT_TIME= %d", intConfigs[CONFIG_INT_RECV_ERROR_WAIT_TIME]); +} + +void processConnect(in_addr address , int fd) +{ + Socket* sock = app->socketMgr->GetSocketByFd(fd); + FTP::SendGreetings(sock); + protoLog->outControl("Recieved FTP Connection from: %s", inet_ntoa(address)); +} + + +void processDisconnect(in_addr /* address */, int fd) +{ + if (sessionStatus.find(fd) != sessionStatus.end()) + sessionStatus.erase(fd); + if (sessionData.find(fd) != sessionData.end()) + sessionData.erase(fd); + protoLog->outControl("Connection form %d closed", fd); +} + +void processRecieve(in_addr /* address */, int fd, char* data) +{ + Socket* sock = app->socketMgr->GetSocketByFd(fd); + stringstream dat(data); + + SessionDataStruct& session = sessionData[fd]; + + string strdata(data); + strdata = trim(data); + + string command; // Command is four character string + dat >> command; + + if (!(command[0] >='a' && command[0] <= 'z') && !(command[0] >='A' && command[0] <= 'Z')) // Invalid command + return; + + FTPStates processCommand = FTP_UNKNOWN; + + if (commandTable.find(lower(command)) != commandTable.end()) + processCommand = commandTable[lower(command)]; + + protoLog->outControl("Recieved Command: %s Procesing Command: %d", command.c_str(), processCommand); + switch (processCommand) + { + case FTP_LOGIN_USER: + { + if (session.loginPrompted) + return; + string user; + dat >> user; + if (!user.length()) + { + FTP::SendCommandResponse(sock, 500); + return; + } + session.username = user; + session.loginPrompted = true; + FTP::SendCommandResponse(sock, 331); // Require Password + break; + } + case FTP_LOGIN_PASS: + { + if (!session.loginPrompted) + return; + string password; + dat >> password; + if (!password.length()) + { + FTP::SendCommandResponse(sock, 500); + return; + } + session.password = password; + protoLog->outDebug("FTP:: User: %s pass: '%s'", session.username.c_str(), session.password.c_str()); + session.loginPrompted = false; + session.loggedIn = true; + FTP::SendCommandResponse(sock, 230); // Authed + break; + } + case FTP_PRINT_WORKING_DIRECTORY: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + FTP::SendSpecialCommandResponse(sock, 200, "'"+ session.actualDir +"' is actual directory."); + break; + } + case FTP_TRANSFER_TYPE: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string type; + dat >> type; + type = type; + if (lower(type)[0] == 'i') + { + session.transferType = TRANSFER_BINARY; + FTP::SendCommandResponse(sock, 200); // ok + break; + } + if (lower(type)[0] == 'a') + { + session.transferType = TRANSFER_ASCII; + FTP::SendCommandResponse(sock, 200); // ok + break; + } + FTP::SendCommandResponse(sock, 500); // error + break; + } + case FTP_SESSION_PORT: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + int a[9], p = 0; + memset (a, 0, 9 * sizeof (int)); + + string addr(strdata.substr(strdata.find_first_of(' '), string::npos)); + string remaining = addr; + + while (remaining.find_first_of(',') != string::npos) + { + string part = remaining.substr(0, remaining.find_first_of(',')); + remaining = remaining.substr(remaining.find_first_of(',')+1, string::npos); + stringstream(part) >> a[p++]; + if (remaining.find_first_of(',') == string::npos) + stringstream(remaining) >> a[p++]; + } + + for (uint8 i = 0; i < 4; i++) + session.ip[i] = a[i]; + session.ip.Restore(); + //protoLog->outDebug("IP Struct: %s %d %d %d %d 0x%08x 0x%08x", + //session.ip.ToChar(), session.ip[0], session.ip[1],session.ip[2],session.ip[3], *(int*)(&session.ip.ipB), *(int*)(&session.ip.ipI.s_addr)); + session.port = a[4] * 256 + a[5]; + session.isPassive = false; + + protoLog->outDebug("Connect via address: %s (%d.%d.%d.%d:%d)", addr.c_str(), a[0], a[1], a[2], a[3], a[4] * 256 + a[5]); + FTP::SendCommandResponse(sock, 200); // ok + break; + } + case FTP_CHANGE_WORKING_DIRECTORY_TO_PARENT: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + session.actualDir = session.parentDir; + FTP::SendSpecialCommandResponse(sock, 250, "CDUP successfull"); + break; + } + case FTP_SESSION_PASSIVE: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + FTP::InitPassiveSock(session); + protoLog->outDebug("Session %s IP: %s Port: %hu", session.isPassive? "Passive" : "Active", session.ip.ToChar(), session.port); + stringstream response; + response << "Entering passive mode."; + response << int(session.ip[0]) << ',' << int(session.ip[1]) << ',' << int(session.ip[2]) << ',' << int(session.ip[3]) << ','; + response << int(session.port / 256) << ',' << int(session.port % 256); + FTP::SendSpecialCommandResponse(sock, 227, response.str().c_str()); + break; + } + case FTP_LIST: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + protoLog->outDebug("Listing Directory: %s",string('.'+session.actualDir).c_str()); + TerminalFuction func("ls", "-la ." + session.actualDir); + char* output = func.RunWithCallback(); + FTP::SendOverDTP(fd, output, strlen(output)); + break; + } + case FTP_CHANGE_WORKING_DIRECTORY: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string dir; + dat >> dir; + if (dir.compare(".") == 0) + { + FTP::SendSpecialCommandResponse(sock, 200, "'"+ session.actualDir +"' is actual directory."); + break; + } + if (dir[0] == '/') + { + session.actualDir = dir; + if (session.actualDir[session.actualDir.length()-1] != '/') + session.actualDir += '/'; + FTP::SendSpecialCommandResponse(sock, 200, "'"+ session.actualDir +"' is actual directory."); + break; + } + if (dir.compare("..") == 0) + { + if (session.actualDir[session.actualDir.length()-1] == '/') + session.actualDir.erase(session.actualDir.length()-1, string::npos); + session.actualDir.erase(session.actualDir.find_last_of('/'), string::npos); + + if (session.actualDir.length() == 0 || session.actualDir[session.actualDir.length()-1] != '/') + session.actualDir += '/'; + FTP::SendSpecialCommandResponse(sock, 200, "'"+ session.actualDir +"' is actual directory."); + break; + } + if (!DirectoryInfo::IsDir('.' + session.actualDir + dir)) + { + FTP::SendCommandResponse(sock, 550); + break; + } + session.actualDir += dir; + if (session.actualDir[session.actualDir.length()-1] != '/') + session.actualDir += '/'; + FTP::SendCommandResponse(sock, 250); + break; + } + case FTP_NOOP: + FTP::SendSpecialCommandResponse(sock, 200, "Noop"); + break; + case FTP_SYST: + FTP::SendSpecialCommandResponse(sock, 200, "Ikaros"); + break; + case FTP_QUIT: + FTP::SendCommandResponse(sock, 221); + sock->Close(); + if (sessionStatus.find(fd) != sessionStatus.end()) + sessionStatus.erase(fd); + if (sessionData.find(fd) != sessionData.end()) + sessionData.erase(fd); + app->socketMgr->CloseSocketByFd(fd); + break; + case FTP_MAKE_DIR: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string dirname = trim(dat.str().substr(dat.str().find_first_of(' '), string::npos)); + string address = '.' + session.actualDir + dirname; + if (DirectoryEntry::CreateDirectory(address) == 0) + FTP::SendSpecialCommandResponse(sock, 257, '"' + dirname + "\" created."); + else + FTP::SendCommandResponse(sock, 450); // Already Exists + break; + } + case FTP_STORAGE_DELETE: + case FTP_REMOVE_DIR: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string filename = trim(dat.str().substr(dat.str().find_first_of(' '), string::npos)); + string address = '.' + session.actualDir + filename; + protoLog->outDebug("Delete File/Directory Name: %s", address.c_str()); + if (filename[0] == '/') + address= '.' + filename; + if (DirectoryEntry::RemoveEntry(address) == 0) + FTP::SendCommandResponse(sock, 250); + else + FTP::SendCommandResponse(sock, 550); // Not Found + break; + } + case FTP_STORAGE_STORE: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string filename = trim(dat.str().substr(dat.str().find_first_of(' '), string::npos)); + string address = '.' + session.actualDir + filename; + if (filename[0] == '/') + address= '.' + filename; + protoLog->outDebug("Store File FileName: %s", address.c_str()); + FTP::RecieveOverDTP(fd, address.c_str()); + break; + } + case FTP_STORAGE_RETRIEVE: + { + if (!session.loggedIn) + { + FTP::SendCommandResponse(sock, 530); + return; + } + string filename = trim(dat.str().substr(dat.str().find_first_of(' '), string::npos)); + string address = '.' + session.actualDir + filename; + if (filename[0] == '/') + address= '.' + filename; + protoLog->outDebug("Requesting File: %s", address.c_str()); + if (FileExists(address) != 0) + { + FTP::SendCommandResponse(sock, 550); // Not Found + break; + } + Files::BinFile file; + char* tmp = (char*) file.readFile(address); + if (!file.is_open()) + { + FTP::SendCommandResponse(sock, 450); // Not Found + break; + } + char* output = new char[file.getLength() + 1]; + memset(output, 0, file.getLength()+1); + memcpy(output, tmp, file.getLength()); + protoLog->outDebug("Sending Requested file: %s length: %lu", address.c_str(), file.getLength()); + FTP::SendOverDTP(fd, output, file.getLength()); + break; + } +// NYI + case FTP_HELP: + case FTP_UNKNOWN: + FTP::SendSpecialCommandResponse(sock, 502, "Command '"+ command +"' "+ responseCodeMessage[502]); + break; + } +} diff --git a/Protocol/FTP/Base.h b/Protocol/FTP/Base.h new file mode 100644 index 0000000..086f06e --- /dev/null +++ b/Protocol/FTP/Base.h @@ -0,0 +1,21 @@ +#include "Includes.cpp" +#include "Adds.cpp" +#include "FTP.cpp" +#include "FileAccessor.cpp" + +#ifdef __cplusplus +extern "C" +{ +#endif + +void processRecieve(in_addr /* address */, int fd, char* data); +void processConnect(in_addr /* address */, int fd); +void processDisconnect(in_addr /* address */, int fd); +void Init(); + + + +#ifdef __cplusplus +} +#endif + diff --git a/Protocol/FTP/CMakeLists.txt b/Protocol/FTP/CMakeLists.txt new file mode 100644 index 0000000..4f5999a --- /dev/null +++ b/Protocol/FTP/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 2.6) + +set (LibraryName FTP) +set (ConfigName ftp.conf) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +add_library(${LibraryName} SHARED Base.cpp) +install(TARGETS ${LibraryName} DESTINATION ${InstallDirectory}) + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") + if (NOT EXISTS "${InstallDirectory}${ConfigName}") + install(FILES ${ConfigName} DESTINATION ${InstallDirectory}) + endif (NOT EXISTS "${InstallDirectory}${ConfigName}") +endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") diff --git a/Protocol/FTP/FTP.cpp b/Protocol/FTP/FTP.cpp new file mode 100644 index 0000000..c689dcf --- /dev/null +++ b/Protocol/FTP/FTP.cpp @@ -0,0 +1,365 @@ +#include "FTP.h" + + +void FTP::SendGreetings(Socket* sock) +{ + stringstream stream; + stream << "220 Server-Ikaros " << stringConfigs[CONFIG_STRING_GREETINGS] << newline; + sock->Send(stream); +} + +void FTP::SendHelloResponse(Socket* sock, std::string name) +{ + stringstream stream; + stream << "250 Hello "<< name << newline; + sock->Send(stream); +} + +void FTP::SendCommandResponse(Socket* sock, int responseCode) +{ + if (responseCodeMessage.find(responseCode) == responseCodeMessage.end()) + return; + + stringstream stream; + stream << responseCode << ' ' << responseCodeMessage[responseCode] << newline; + sock->Send(stream); +} + +void FTP::SendSpecialCommandResponse(Socket* sock, int responseCode, string text) +{ + if (responseCodeMessage.find(responseCode) == responseCodeMessage.end()) + return; + + stringstream stream; + stream << responseCode << ' ' << text << newline; + sock->Send(stream); +} + +void* SendData(void* args) +{ + protoLog->outDebug("SendData Begin"); + SessionSendStruct* sendStat = (SessionSendStruct*) args; + Socket* sock = sendStat->so; + SessionDataStruct& session = sendStat->s; + char* data = sendStat->d; + size_t dataLength = sendStat->l; + FTP::SendCommandResponse(sock, 150); + + int sendReturn = 0, sleepTime = intConfigs[CONFIG_INT_SEND_WAIT_TIME], errSleepTime = intConfigs[CONFIG_INT_SEND_ERROR_WAIT_TIME]; + size_t sended = 0, sendingPart = intConfigs[CONFIG_INT_MAX_DATA_SEGMENT_SIZE]; + bool interrupt = false; + + if (!session.isPassive) + { + TCPSocket* connection = new TCPSocket(); + int i = connection->Connect(session.ip.ToChar(), session.port); + if (!connection->Connected()) + { + FTP::SendCommandResponse(sock, 425); // Cannot open connection + session.DTPActive = false; + session.activeSend = NULL; + session.abortTranfser = false; + protoLog->outDebug("Cannot connect to: %s:%d connection: %d", session.ip.ToChar(), session.port, i); + delete connection; + delete data; + delete sendStat; + return NULL; + } + + while (!session.abortTranfser && connection->Connected() && !interrupt) + { + sendReturn = connection->Send(data + sended, dataLength - sended > sendingPart ? sendingPart : dataLength - sended, 0 ); + //protoLog->outDebug("Sended: %d bytes from %lu remaining: %lu", sendReturn, dataLength, dataLength - sended); + if (sendReturn == -1) + { + if (errno != EAGAIN) + break; + usleep(errSleepTime); + continue; + } + if (sendReturn == 0) + { + interrupt = true; + break; + } + if (sendReturn > 0) + sended += sendReturn; + if ((dataLength - sended == 0)) + break; + if (sleepTime) + usleep(sleepTime); + } + connection->Close(); + delete connection; + } + else + { + int& lSock = session.passiveSock; + + if (lSock < 0) + { + FTP::SendCommandResponse(sock, 425); + session.DTPActive = false; + session.activeSend = NULL; + session.abortTranfser = false; + lSock = close(lSock); + delete data; + delete sendStat; + return NULL; + } + + struct sockaddr_in peer; + unsigned int peerSize = sizeof(peer); + int newSocket = accept(lSock, (sockaddr*)&peer, &peerSize); + Socket* pSock = new Socket(newSocket, peer); + + while (!session.abortTranfser && !interrupt) + { + sendReturn = pSock->Send(data + sended, dataLength - sended > sendingPart ? sendingPart : dataLength - sended, 0 ); + //protoLog->outDebug("Sended: %d bytes from %lu remaining: %lu", sendReturn, dataLength, dataLength - sended); + if (sendReturn == -1) + { + if (errno != EAGAIN) + break; + usleep(errSleepTime); + continue; + } + if (sendReturn == 0) + { + interrupt = true; + break; + } + if (sendReturn > 0) + sended += sendReturn; + if ((dataLength - sended == 0)) + break; + if (sleepTime) + usleep(sleepTime); + } + pSock->Close(); + lSock = close(lSock); + delete pSock; + } + + if (!interrupt) + FTP::SendCommandResponse(sock, 226); + if (session.abortTranfser) + FTP::SendCommandResponse(sock, 426); + delete data; + delete sendStat; + session.DTPActive = false; + session.activeSend = NULL; + session.abortTranfser = false; + protoLog->outDebug("SendData End session: %s", session.DTPActive? "Data Tranfsering": "Data Tranfser Completed" ); + return NULL; +} + +void* RecvData(void* args) +{ + protoLog->outDebug("RecvData Begin"); + SessionRecvStruct* recvStat = (SessionRecvStruct*) args; + Socket* sock = recvStat->so; + SessionDataStruct& session = recvStat->s; + const char* fileName = recvStat->f; + FTP::SendCommandResponse(sock, 150); + + int recvReturn = 0, sleepTime = intConfigs[CONFIG_INT_RECV_WAIT_TIME], errSleepTime = intConfigs[CONFIG_INT_RECV_ERROR_WAIT_TIME]; + size_t recieved = 0, recievePart = intConfigs[CONFIG_INT_MAX_DATA_SEGMENT_SIZE]; + bool interrupt = false; + BinnaryData* recvData = new BinnaryData(); + char recievedData[recievePart + 1]; + + if (!session.isPassive) + { + TCPSocket* connection = new TCPSocket(); + int i = connection->Connect(session.ip.ToChar(), session.port); + if (!connection->Connected()) + { + FTP::SendCommandResponse(sock, 425); // Cannot open connection + session.DTPActive = false; + session.activeRecv = NULL; + session.abortTranfser = false; + protoLog->outDebug("Cannot connect to: %s:%d connection: %d", session.ip.ToChar(), session.port, i); + delete connection; + delete recvStat; + return NULL; + } + + + while (!session.abortTranfser && connection->Connected() && !interrupt) + { + memset(recievedData, 0, recievePart + 1); + recvReturn = connection->Recv(recievedData, recievePart, 0 ); + //protoLog->outDebug("Recieved: %d bytes Actual file size: %lu total recieved: %lu", recvReturn, recvData->size() + recvReturn, recieved); + if (recvReturn == -1) + { + if (errno != EAGAIN) + break; + usleep(errSleepTime); + continue; + } + if (recvReturn == 0) + { + interrupt = true; + break; + } + if (recvReturn > 0) + { + recieved += recvReturn; + recvData->write(recievedData, recvReturn); + } + if (sleepTime) + usleep(sleepTime); + } + connection->Close(); + delete connection; + } + else + { + int& lSock = session.passiveSock; + + if (lSock < 0) + { + FTP::SendCommandResponse(sock, 425); + session.DTPActive = false; + session.activeRecv = NULL; + session.abortTranfser = false; + lSock = close(lSock); + delete recvStat; + return NULL; + } + + struct sockaddr_in peer; + unsigned int peerSize = sizeof(peer); + int newSocket = accept(lSock, (sockaddr*)&peer, &peerSize); + Socket* pSock = new Socket(newSocket, peer); + + while (!session.abortTranfser && !interrupt) + { + memset(recievedData, 0, recievePart + 1); + recvReturn = pSock->Recieve(recievedData, recievePart, 0 ); + //protoLog->outDebug("Recieved: %d bytes Actual file size: %lu total recieved: %lu", recvReturn, recvData->size() + recvReturn, recieved); + if (recvReturn == -1) + { + if (errno != EAGAIN) + break; + usleep(errSleepTime); + continue; + } + if (recvReturn == 0) + { + interrupt = true; + break; + } + if (recvReturn > 0) + { + recieved += recvReturn; + recvData->write(recievedData, recvReturn); + } + if (sleepTime) + usleep(sleepTime); + } + pSock->Close(); + lSock = close(lSock); + delete pSock; + } + + if (!session.abortTranfser) + FTP::SendCommandResponse(sock, 226); + if (session.abortTranfser) + FTP::SendCommandResponse(sock, 426); + + protoLog->outDebug("RecvData Recieved: %lu Bytes Recieved data Size: %lu", recieved, recvData->size()); + Files::BinFile file; + file.open(fileName, ios_base::trunc | ios_base::binary | ios_base::out); + file.write((const char*)recvData, recvData->size()); + file.close(); + recvData->clear(); + + delete recvStat; + session.DTPActive = false; + session.activeRecv = NULL; + session.abortTranfser = false; + protoLog->outDebug("RecvData End session: %s", session.DTPActive? "Data Tranfsering": "Data Tranfser Completed" ); + return NULL; +} + +void FTP::SendOverDTP(int fd, char* data, size_t dataLength) +{ + if (!data) + return; + SessionDataStruct& session = sessionData[fd]; + Socket* sock = app->socketMgr->GetSocketByFd(fd); + protoLog->outDebug("Sending %d bytes over DTP to: %s:%d Mode: %s", dataLength, session.ip.ToChar(), session.port, session.isPassive? "Passive" : "Active"); + SessionSendStruct* s = new SessionSendStruct(session, sock, data, dataLength); + session.DTPActive = true; + session.activeSend = s; + session.abortTranfser = false; + Thread::CreateThread(&SendData, (void*) s); +} + +void FTP::RecieveOverDTP(int fd, const char* fileName) +{ + if (!fileName) + return; + SessionDataStruct& session = sessionData[fd]; + Socket* sock = app->socketMgr->GetSocketByFd(fd); + protoLog->outDebug("Recv over DTP from: %s:%d Mode: %s", session.ip.ToChar(), session.port, session.isPassive? "Passive" : "Active"); + SessionRecvStruct* s = new SessionRecvStruct(session, sock, fileName); + session.DTPActive = true; + session.activeRecv = s; + session.abortTranfser = false; + Thread::CreateThread(&RecvData, (void*) s); +} + +void FTP::InitPassiveSock(SessionDataStruct& session) +{ + int& sock = session.passiveSock; + close(sock); + int r = 0; + struct sockaddr_in dest; + sock = socket(AF_INET, SOCK_STREAM, 0) ; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof sock); + + if (sock < 0) + { + protoLog->outError("DTP Passive Socket Creation failed. Error: %d", errno); + } + + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = 0; + dest.sin_addr.s_addr = inet_addr("0.0.0.0"); + //Bind + r = bind(sock, (struct sockaddr*)&dest, sizeof(dest)); + if (r == -1) + { + protoLog->outError("DTP Passive Socket Bind Returned Error: %d", errno); + close(sock); + } + + //Listen + r = listen(sock, 2); + if (r == -1) + { + protoLog->outError("DTP Passive Socket Listen Returned Error: %d", errno); + close(sock); + } + else + { + struct sockaddr_in info; + bzero(&info, sizeof(info)); + socklen_t len = sizeof (info); + if (getsockname(sock, (struct sockaddr*)&info, &len) == 0) + { + session.isPassive = true; + session.port = ntohs(info.sin_port); + session.ip = IP(info.sin_addr); + } + else + { + session.isPassive = false; + session.port = 0; + } + } +} diff --git a/Protocol/FTP/FTP.h b/Protocol/FTP/FTP.h new file mode 100644 index 0000000..cb5b541 --- /dev/null +++ b/Protocol/FTP/FTP.h @@ -0,0 +1,176 @@ +#include "Includes.cpp" +#include "defines.h" + +#include "ConfigMgr.cpp" + +#ifndef __FTP +#define __FTP + + + +enum FTPStates +{ + FTP_LOGIN_USER = 0, + FTP_LOGIN_PASS, + FTP_CHANGE_WORKING_DIRECTORY, + FTP_PRINT_WORKING_DIRECTORY, + FTP_CHANGE_WORKING_DIRECTORY_TO_PARENT, + FTP_LIST, + FTP_QUIT, + FTP_STORAGE_STORE, + FTP_TRANSFER_TYPE, + FTP_STORAGE_RETRIEVE, + FTP_STORAGE_DELETE, + FTP_MAKE_DIR, + FTP_REMOVE_DIR, + FTP_HELP, + FTP_NOOP, + FTP_SYST, + FTP_SESSION_PORT, + FTP_SESSION_PASSIVE, + FTP_UNKNOWN, +}; + +enum TransferType +{ + TRANSFER_BINARY, + TRANSFER_ASCII +}; + +class IP +{ + public: + IP(): ipC(NULL) { memset(ipB, 0, 4); ByteToInAddr(ipB); } + IP(byte i[4]) { ByteToInAddr(i); ipC = inet_ntoa(ipI); } + IP(in_addr i) { ipC = inet_ntoa(i); ipI = i; InAddrToByte(i); } + IP(char* i): ipC(i) { inet_aton(i, &ipI); InAddrToByte(ipI); } + + + void InAddrToByte(in_addr i) { memcpy(ipB, &i.s_addr, 4); } + void ByteToInAddr(byte* i) { memcpy(&ipI.s_addr, i, 4); } + + char* ToChar() const { return ipC; } + + void Restore() { ByteToInAddr(ipB); ipC = inet_ntoa(ipI); } + + operator in_addr() { return ipI; } + operator char*() { return ipC; } + byte& operator [](const int location) { return ipB[location]; } + + protected: + byte ipB[4]; // addr + in_addr ipI; + char* ipC; +}; + +struct SessionSendStruct; +struct SessionRecvStruct; + +struct SessionDataStruct +{ + SessionDataStruct(): username(""), password(""), parentDir("/"), actualDir("/"), + port(20), passiveSock(0), loginPrompted(false), loggedIn(false), isPassive(false), DTPActive(false), abortTranfser(false), + activeSend(NULL), activeRecv(NULL) { } + + string username; + string password; + string parentDir; + string actualDir; + TransferType transferType; + + IP ip; + uint16 port; + + int passiveSock; + + bool loginPrompted; + bool loggedIn; + bool isPassive; + + bool DTPActive; + bool abortTranfser; + + SessionSendStruct* activeSend; + SessionRecvStruct* activeRecv; +}; + +struct SessionSendStruct +{ + SessionSendStruct(SessionDataStruct& sdata, Socket* sock, char* data, size_t length): + s(sdata), so(sock), d(data), l(length) { } + + SessionDataStruct& s; + Socket* so; + char* d; + size_t l; +}; + +struct SessionRecvStruct +{ + SessionRecvStruct(SessionDataStruct& sdata, Socket* sock, const char* fileName): + s(sdata), so(sock), f(fileName) { } + + SessionDataStruct& s; + Socket* so; + const char* f; +}; + +std::map sessionStatus; +std::map sessionData; + +SimpleLog* protoLog; +ConfigMgr* configMgr; + +std::map responseCodeMessage; + +#ifdef __cplusplus +extern "C" +{ +#endif + +class FTP +{ + public: + static void SendGreetings(Socket* sock); + static void SendHelloResponse(Socket* sock, std::string); + static void SendCommandResponse(Socket* sock, int responseCode); + static void SendSpecialCommandResponse(Socket* sock, int responseCode, string text); + static void SendOverDTP(int fd, char* data, size_t dataLength); + static void RecieveOverDTP(int fd, const char* fileName); + static void InitPassiveSock(SessionDataStruct& session); +}; + +#ifdef __cplusplus +} +#endif + + +enum BoolConfigs +{ + CONFIG_BOOL_DEBUG, + CONFIG_BOOL_CONTROL, + MAX_BOOL_CONFIGS +}; + +enum StringConfigs +{ + CONFIG_STRING_GREETINGS, + MAX_CONFIG_STRING +}; + +enum IntConfigs +{ + CONFIG_INT_MAX_DATA_SEGMENT_SIZE, + CONFIG_INT_SEND_WAIT_TIME, + CONFIG_INT_SEND_ERROR_WAIT_TIME, + CONFIG_INT_RECV_WAIT_TIME, + CONFIG_INT_RECV_ERROR_WAIT_TIME, + MAX_CONFIG_INT + +}; + +bool boolConfigs[MAX_BOOL_CONFIGS]; +string stringConfigs[MAX_CONFIG_STRING]; +int intConfigs[MAX_CONFIG_INT]; + +#endif // __FTP diff --git a/Protocol/FTP/FileAccessor.cpp b/Protocol/FTP/FileAccessor.cpp new file mode 100755 index 0000000..71a56e1 --- /dev/null +++ b/Protocol/FTP/FileAccessor.cpp @@ -0,0 +1,80 @@ +#include "FileAccessor.h" + + +FileNameVector const DirectoryInfo::GetFiles() +{ + if (!entryName) + return FileNameVector(); + + if (dir) + return FileNameVector(); + + if (files.size()) + return files; + + if (!dir) + dir = opendir(entryName); + + if (!dir) + { + err = errno; + if (err == ENOTDIR) + isDir = false; + return FileNameVector(); + } + + files.clear(); + struct dirent* dp = NULL; + errno = 0; + while ((dp = readdir(dir)) != NULL) + { + files.push_back(dp->d_name); + } + if (errno) + err = errno; + + closedir(dir); + return files; +} + +bool DirectoryInfo::IsDir(const char* dirName) +{ + DIR* dir = opendir(dirName); + + if (!dir) + return false; + + closedir(dir); + return true; +} + +int DirectoryEntry::Remove() +{ + int ret = 0; + ret = remove(fileName); + if (ret == 0) + exists = false; + else + { + err = errno; + if (err == ENOENT) + exists = false; + } + return ret; +} + +int DirectoryEntry::Rename(char* newname) +{ + int ret = 0; + ret = rename(fileName, newname); + if (ret == 0) + fileName = newname; + else + { + err = errno; + if (err == ENOENT) + exists = false; + } + return ret; +} + diff --git a/Protocol/FTP/FileAccessor.h b/Protocol/FTP/FileAccessor.h new file mode 100755 index 0000000..98d0608 --- /dev/null +++ b/Protocol/FTP/FileAccessor.h @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file.h" + +typedef std::vector FileNameVector; +typedef unsigned int uint32; +typedef unsigned long uint64; + +class DirectoryEntryInfo +{ + public: + DirectoryEntryInfo(char* _entryName, struct stat _fileStat): fileStat(_fileStat), entryName(_entryName) { } + uint32 GetMode() const { return fileStat.st_mode; } + uint32 GetGID() const { return fileStat.st_gid; } + uint32 GetUID() const { return fileStat.st_uid; } + uint64 GetSize() const { return fileStat.st_size; } + time_t GetLastAccess() const { return fileStat.st_atime; } + time_t GetLastModifycation() const { return fileStat.st_mtime; } + time_t GetLastStatusChange() const { return fileStat.st_ctime; } + char* GetEntryName() const { return entryName; } + + + protected: + struct stat fileStat; + char* entryName; +}; + +DirectoryEntryInfo const* GetFileInfo(char* fileName) +{ + struct stat fileStat; + if (stat(fileName, &fileStat) == 0) + return new DirectoryEntryInfo(fileName, fileStat); + else + return NULL; +} + +class DirectoryInfo : public DirectoryEntryInfo +{ + public: + DirectoryInfo(char* _directoryName, struct stat _dirStat): + DirectoryEntryInfo(_directoryName, _dirStat), dir(NULL), isDir(true), err(0) { } + + char* GetDirectoryName() const { return entryName; } + FileNameVector const GetFiles(); + + bool IsDirectory() const { return isDir; } + uint32 GetError() const { return err; } + static bool IsDir(const char* dirName); + static bool IsDir(string dirName) { return DirectoryInfo::IsDir(dirName.c_str()); } + protected: + DIR* dir; + FileNameVector files; + bool isDir; + uint32 err; +}; + +class DirectoryEntry // Used for manipulation with files and folders +{ + public: + DirectoryEntry(const char* _fileName): fileName(_fileName), exists(true), err(0) { } + DirectoryEntry(string _fileName): fileName(_fileName.c_str()), exists(true), err(0) { } + int Rename(char* newname); + int Remove(); + + uint32 GetError() const { return err; } + bool Exists() const { return exists; } + const char* GetFileName() const { return fileName; } + + static int RenameEntry(const char* oldname, const char* newname) { return rename(oldname, newname); } + static int RemoveEntry(const char* filename) { return remove(filename); } + static int RemoveEntry(string filename) { return remove(filename.c_str()); } + static int CreateDirectory(const char* dirname, uint32 mode = 0x01FF) { return mkdir(dirname, mode); } + static int CreateDirectory(string dirname, uint32 mode = 0x01FF) { return mkdir(dirname.c_str(), mode); } + protected: + const char* fileName; + bool exists; + uint32 err; +}; + +class TerminalFuction // Used for manipulation output of applications ran from terminal USEABLE ONLY ON LINUX +{ + public: + TerminalFuction(string _program, string _args): program(_program), args(_args) { } + int Run() const { return system((program + " " + args).c_str()); } + char* RunWithCallback(int* returnValue = NULL) const + { + int ret = 0; + stringstream call; + call << program << ' ' << args << " > tmpfile.txt"; + //printf("\nCall: %s\n",call.str().c_str()); + ret = system(call.str().c_str()); + if (returnValue) + *returnValue = ret; + Files::AsciiFile file; + char* tmp = file.readFile("tmpfile.txt"); + char* output = new char[strlen(tmp)+1]; + memset(output, 0, strlen(tmp)+1); + memcpy(output, tmp, strlen(tmp)); + DirectoryEntry::RemoveEntry("tmpfile.txt"); + return output; + } + + private: + std::string program; + std::string args; +}; diff --git a/Protocol/FTP/defines.h b/Protocol/FTP/defines.h new file mode 100644 index 0000000..c26f6ed --- /dev/null +++ b/Protocol/FTP/defines.h @@ -0,0 +1,14 @@ +#ifndef __Defs +#define __Defs + +#define newline "\r\n" + + +typedef unsigned char Byte; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned short uint16; + + +#endif // __Defs diff --git a/Protocol/FTP/ftp.conf b/Protocol/FTP/ftp.conf new file mode 100644 index 0000000..d0862d8 --- /dev/null +++ b/Protocol/FTP/ftp.conf @@ -0,0 +1,33 @@ +# Greetings -- string value +# sets message to be sent when client connects +Greetings= Welcome to Ikaros, multifunctional server based FTP + +# Debug -- bool value +# sets protocol debug output +# 0 -- disabled +# 1 -- enabled +Debug = 1 + +# Control -- bool value +# sets protocol control output +# 0 -- disabled +# 1 -- enabled +Control = 0 + +# MaxSegmentSize -- int value +# sets maximal sending segment size +# used when protocol sends over DTP file thats size > MaxSegmentSize +# that file is segmented into parts with maximal size of this value +MaxSegmentSize = 35000 + +# SendErrprWaitTime -- int value +# sets sending wait time +# used when protocol sends over DTP file thats size > MaxSegmentSize +# where protocol recieves EAGAIN usleep (micro sleep) is called with this value +SendErrorWaitTime = 20 + +# SendWaitTime -- int value +# sets sending wait time +# used when protocol sends over DTP file thats size > MaxSegmentSize +# usleep (micro sleep) is called with this value +SendWaitTime = 0 diff --git a/Protocol/HTTP/Adds.cpp b/Protocol/HTTP/Adds.cpp new file mode 100644 index 0000000..d461ee6 --- /dev/null +++ b/Protocol/HTTP/Adds.cpp @@ -0,0 +1,92 @@ +#include "Adds.h" + +#include + +void FileAddress::Parse() +{ + // At the begining there was an file; + + size_t pos = file.rfind('/'); + if (pos == string::npos) + { + isValid = false; + return; // We Have a Not Valid File Address Here + } + string Tfile = file.substr(pos+1, string::npos); + path = file.substr(0, pos+1); + // sLog->outString("FILE: '%s'", file.c_str()); + // sLog->outString("TFILE: '%s'", Tfile.c_str()); + // sLog->outString("PATH: '%s'", path.c_str()); + pos = Tfile.find('?'); + if (pos == string::npos) + fileName = Tfile; + else + { + params = Tfile.substr(pos+1, string::npos); + fileName = Tfile.substr(0, pos); + } + // sLog->outString("FILENAME: '%s'", fileName.c_str()); + // sLog->outString("PARAMS: '%s'", params.c_str()); + + isValid = true; +} + + +bool isWithinRootDir(string file) +{ + int deep = 0; + // sLog->outString("::isWithinRootDir: '%s'", file.c_str()); + if (file[0] == '/') + file = file.substr(1, string::npos); + while (file.find('/') != string::npos) + { + string test = file.substr(0, file.find('/')); + if (!test.length() && deep == 0) + return false; // Point on Root Directory + if (!test.length()) + break; + + if (!test.compare("..")/* == 0*/) + deep--; + else + deep++; + file = file.substr(file.find('/'), string::npos); + } + if (deep < 0) + return false; + return true; +} + +int FileExists(string file) +{ + struct stat buffer; + int ret = stat(file.c_str(), &buffer); + return ret == 0 ? 0 : errno; +} + +string lower(string in) +{ + string out = in; + for (uint32 i = 0; i< in.length();i++) + if (out[i] >= 'A' && out[i] <= 'Z') + out[i] = out[i] + 32; + return out; +} + +string trim(string in) +{ + size_t pos = in.find_first_not_of(" \r\n\t"); + in.erase(0, pos ); + pos = in.find_last_not_of(" \r\n\t"); + if (pos == string::npos) + return in; + in.erase(pos + 1, string::npos); + return in; +} + +string toString(size_t i) +{ + stringstream s; + s << i; + return s.str(); +} diff --git a/Protocol/HTTP/Adds.h b/Protocol/HTTP/Adds.h new file mode 100644 index 0000000..9bf81e0 --- /dev/null +++ b/Protocol/HTTP/Adds.h @@ -0,0 +1,48 @@ +#include "Includes.cpp" + + +#ifndef __Adds +#define __Adds + +typedef std::multimap Vars; + +enum RequestMethod +{ + METHOD_GET = 1, + METHOD_PUT, + METHOD_POST, + METHOD_HEAD +}; + +struct HTTPHeader +{ + struct HTTPRequest + { + RequestMethod method; + string RequestedURI; + Byte Version; + } Request; + string Host; + string UserAgent; + Vars additions; +}; + +struct FileAddress +{ + FileAddress(): isValid(false){ } + FileAddress(string f): file(f), isValid(false) { Parse(); } + string path; + string fileName; + string params; + + string file; + void Parse(); + void Parse(string s) { file = s; Parse(); } + bool isValid; +}; + +bool isWithinRootDir(string file); +int FileExists(string file); +string toString(size_t i); + +#endif // __Adds diff --git a/Protocol/HTTP/Base.cpp b/Protocol/HTTP/Base.cpp new file mode 100755 index 0000000..42381c8 --- /dev/null +++ b/Protocol/HTTP/Base.cpp @@ -0,0 +1,216 @@ +#include "Includes.cpp" +#include "HTTP.cpp" +#include "Adds.cpp" + + + + + +void Init() +{ + configMgr = new ConfigMgr("http.conf", NULL, 0); + protoLog = new SimpleLog(boolConfigs[CONFIG_BOOL_CONTROL], boolConfigs[CONFIG_BOOL_DEBUG], "Protocol.log"); + LoadConfig(); + InitStrings(); + InitErrorPages(); +} + +void InitStrings() +{ + errorStrings.insert(std::make_pair(200, "OK")); + errorStrings.insert(std::make_pair(404, "File Not Found")); + errorStrings.insert(std::make_pair(403, "Access Forbidden")); + errorStrings.insert(std::make_pair(500, "Internal Server Error")); + protoLog->outDebug("Initiated Error Strings Actual strings: %u", errorStrings.size()); +} + +void InitErrorPages() +{ + errorPages.insert(std::make_pair(404, +"\n\ + \n\ + 404. Not Found\n\ + \n\ + \n\ + \n\ +
\n\ +

Page Not Found

\n\ +

File you are requesting cannot be found on this server.

\n\ +
\n\ + \n\ +\n" +)); + + errorPages.insert(std::make_pair(403, +"\n\ + \n\ + 403. Access Forbidden\n\ + \n\ + \n\ + \n\ +
\n\ +

Access Forbidden

\n\ +

You don't have a rights to view this file.

\n\ +
\n\ + \n\ +")); + errorPages.insert(std::make_pair(500, +"\n\ + \n\ + 500. Internal Server Error\n\ + \n\ + \n\ + \n\ +
\n\ +

Internal Server Error

\n\ +

This Unknown error may occur from time to time.

\n\ +
\n\ + \n\ +")); + protoLog->outDebug("Initiated Error Pages Actual pages: %u", errorPages.size()); +} + +void DebugConfig() +{ + protoLog->outDebug("CONFIG_BOOL_ALLOW_DEFAULT_INDEX= %s", toString(boolConfigs[CONFIG_BOOL_ALLOW_DEFAULT_INDEX])); + protoLog->outDebug("CONFIG_BOOL_DEBUG= %s", toString(boolConfigs[CONFIG_BOOL_DEBUG])); + protoLog->outDebug("CONFIG_BOOL_CONTROL= %s", toString(boolConfigs[CONFIG_BOOL_CONTROL])); + + protoLog->outDebug("CONFIG_STRING_DEFAULT_INDEX_FILE= '%s'", stringConfigs[CONFIG_STRING_DEFAULT_INDEX_FILE].c_str()); + protoLog->outDebug("CONFIG_STRING_HOSTNAME= '%s'", stringConfigs[CONFIG_STRING_HOSTNAME].c_str()); + protoLog->outDebug("CONFIG_STRING_ROOT_DIR= '%s'", stringConfigs[CONFIG_STRING_ROOT_DIR].c_str()); + + protoLog->outDebug("CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE= '%d'", intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE]); + protoLog->outDebug(); +} +void LoadConfig() +{ + boolConfigs[CONFIG_BOOL_ALLOW_DEFAULT_INDEX] = configMgr->LoadBoolConfig("AllowIndexFile", true); + boolConfigs[CONFIG_BOOL_DEBUG] = configMgr->LoadBoolConfig("Debug", true); + boolConfigs[CONFIG_BOOL_CONTROL] = configMgr->LoadBoolConfig("Control", true); + + stringConfigs[CONFIG_STRING_DEFAULT_INDEX_FILE] = configMgr->LoadStringConfig("IndexFileName", "index.html"); + stringConfigs[CONFIG_STRING_HOSTNAME] = configMgr->LoadStringConfig("Hostname", "localhost"); + stringConfigs[CONFIG_STRING_ROOT_DIR] = configMgr->LoadStringConfig("RootDirectory", "./"); + + intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE] = configMgr->LoadIntConfig("MaximalMainThreadFileSize", 40000); + if (intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE] <= 0) + { + protoLog->outError("MaximalMainThreadFileSize must be > 0 (configured value: %d) setting back to default 40000", + intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE]); + intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE] = 40000; + } + + if (stringConfigs[CONFIG_STRING_ROOT_DIR][stringConfigs[CONFIG_STRING_ROOT_DIR].length()-1] == '/') + stringConfigs[CONFIG_STRING_ROOT_DIR].erase(stringConfigs[CONFIG_STRING_ROOT_DIR].length()-1, 1); + + DebugConfig(); +} + +void processRecieve(in_addr /* address */, int fd, char* data) +{ + + Socket* sock = app->socketMgr->GetSocketByFd(fd); + + BinnaryData dat(data, strlen(data)); + HTTPHeader header; + + string method; + dat >> method; + + if (lower(method).compare("get") == 0) + header.Request.method = METHOD_GET; + else + if (lower(method).compare("post") == 0) + header.Request.method = METHOD_POST; + else + if (lower(method).compare("head") == 0) + header.Request.method = METHOD_HEAD; + else + return; // Unsupported Method + + string RequestedFile; + dat >> RequestedFile; + header.Request.RequestedURI = RequestedFile; // + + string version; + dat >> version; + string line; + do + { + string line = trim(dat.getline()); + if (line.find(':') != string::npos) + { + string property = trim(line.substr(0, line.find(':'))); + string value = trim(line.substr(line.find(':')+1, string::npos)); + if (lower(property).compare("host") == 0) + header.Host = value; + else + if (lower(property).compare("user-agent") == 0) + header.UserAgent = value; + else + header.additions.insert(std::make_pair(lower(property), value)); + // sLog->outString("Property: '%s' Value: '%s'", property.c_str(), value.c_str()); + } + if (!line.length()) + break; + } while (true); + protoLog->outDebug("FD: %d Requesting File: %s", fd, RequestedFile.c_str()); + + + FileAddress file(RequestedFile); + if (file.fileName.length() == 0) + { + if (boolConfigs[CONFIG_BOOL_ALLOW_DEFAULT_INDEX]) + file.fileName = stringConfigs[CONFIG_STRING_DEFAULT_INDEX_FILE]; + else + { + protoLog->outControl("HTTP Error: 404 Requesting Default Page (Not Enabled)"); + HTTPResponse::SendErrorPage(sock, 404); + return; + } + } + + // sLog->outString("Recieved Packet:\n%s",dat.TextLike().c_str()); + // sLog->outString("File: %s is %s", RequestedFile.c_str(), file.isValid? "valid":"invalid" ); + + // sLog->outString("Recieved HTTP Request: Method: %s File: %s Path: %s", method.c_str(), file.fileName.c_str(), file.path.c_str()); + + if (!isWithinRootDir(file.path + file.fileName)) // 403 Forbidden + { + HTTPResponse::SendErrorPage(app->socketMgr->GetSocketByFd(fd), 403); + return; + } + int ret; + switch (ret = FileExists(stringConfigs[CONFIG_STRING_ROOT_DIR] + file.path + file.fileName)) + { + case 0: // All OK + { + switch (header.Request.method) + { + case METHOD_GET: + case METHOD_POST: + HTTPResponse::SendDirectPage(sock, file.path + file.fileName); + break; + case METHOD_HEAD: + HTTPResponse::SendHeadPage(sock, file.path + file.fileName); + break; + case METHOD_PUT: + default: + break; + } + break; + } + case EACCES: + { + protoLog->outControl("HTTP Error: 403 Requesting File: %s", string(stringConfigs[CONFIG_STRING_ROOT_DIR] + file.path + file.fileName).c_str()); + HTTPResponse::SendErrorPage(sock, 403); + break; + } + default: + protoLog->outControl("HTTP Error: 404 Requesting File: %s", string(stringConfigs[CONFIG_STRING_ROOT_DIR] + file.path + file.fileName).c_str()); + HTTPResponse::SendErrorPage(sock, 404); + break; + } + +} diff --git a/Protocol/HTTP/CMakeLists.txt b/Protocol/HTTP/CMakeLists.txt new file mode 100644 index 0000000..681578d --- /dev/null +++ b/Protocol/HTTP/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 2.6) + +set (LibraryName HTTP) +set (ConfigName http.conf) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +add_library(${LibraryName} SHARED Base.cpp) +install(TARGETS ${LibraryName} DESTINATION ${InstallDirectory}) + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") + if (NOT EXISTS "${InstallDirectory}${ConfigName}") + install(FILES ${ConfigName} DESTINATION ${InstallDirectory}) + endif (NOT EXISTS "${InstallDirectory}${ConfigName}") +endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") diff --git a/Protocol/HTTP/HTTP.cpp b/Protocol/HTTP/HTTP.cpp new file mode 100644 index 0000000..ba01ca3 --- /dev/null +++ b/Protocol/HTTP/HTTP.cpp @@ -0,0 +1,119 @@ +#include "HTTP.h" + +void* SendOverNewThread(void* args) +{ + SeparateThreadedSendingData* data = (SeparateThreadedSendingData*) args; + if (!data->sock) + return NULL; + if (data->dat) + { + data->sock->Send(*data->dat); + delete data->dat; + } + else + if (data->stream) + { + data->sock->Send(*data->stream); + delete data->stream; + } + else + if (data->data) + { + data->sock->Send(data->data, data->length); + } + delete data; + return NULL; +} + + +void HTTPResponse::SendErrorPage(Socket* socket, uint32 ErrorId) +{ + if (errorStrings.find(ErrorId) == errorStrings.end()) + return; + if (errorPages.find(ErrorId) == errorStrings.end()) + return; + + stringstream* stream = new stringstream; + + string content = string(errorPages[ErrorId]); + + *stream << "HTTP/1.1 "; + *stream << ErrorId << " " << errorStrings[ErrorId] << newline; + *stream << "Server: Ikaros" << newline; + *stream << "Host: " << stringConfigs[CONFIG_STRING_HOSTNAME] << newline; + *stream << "Connection: close" << newline; + *stream << "Content-Length: " << content.length() << newline; + //stream << "Content-Type: text/html" << newline ; + *stream << newline; + *stream << content; + + SeparateThreadedSendingData* threadData = new SeparateThreadedSendingData(socket, stream); + if (content.length() > size_t(intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE])) + Thread::CreateThread(SendOverNewThread, (void*) threadData); + else + { + socket->Send(*stream); + delete stream; + } +} + + +void HTTPResponse::SendDirectPage(Socket* socket, string file) +{ + BinnaryData* stream = new BinnaryData(); + Files::BinFile content; + content.readFile(stringConfigs[CONFIG_STRING_ROOT_DIR] + file); + + *stream << "HTTP/1.1 200 OK" << newline; + *stream << "Server: Ikaros" << newline; + *stream << "Host: " << stringConfigs[CONFIG_STRING_HOSTNAME] << newline; + *stream << "Connection: close" << newline; + *stream << "Content-Length: " << toString(content.getLength()).c_str() << newline; + //stream << "Content-Type: text/html" << newline ; + *stream << newline ; + stream->append(content.toByteArray(), content.getLength()); + + SeparateThreadedSendingData* threadData = new SeparateThreadedSendingData(socket, stream); + if (stream->size() > size_t(intConfigs[CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE])) + Thread::CreateThread(SendOverNewThread, (void*) threadData); + else + { + socket->Send(*stream); + delete stream; + delete threadData; + } + content.clear(); +} + +void HTTPResponse::SendHeadPage(Socket* socket, string file) +{ + stringstream stream; + Files::AsciiFile content; + content.sreadFile(stringConfigs[CONFIG_STRING_ROOT_DIR] + file); + + stream << "HTTP/1.1 200 OK" << newline; + stream << "Server: Ikaros" << newline; + stream << "Host: " << stringConfigs[CONFIG_STRING_HOSTNAME] << newline; + stream << "Connection: close" << newline; + stream << "Content-Length: " << content.getLength() << newline; + //stream << "Content-Type: text/html" << newline << newline; + + socket->Send(stream); +} + +void HTTPResponse::KillSpartans(Socket* socket) +{ + stringstream stream; + string str = "I'm Going TO KILL YARR SPARTANS!!!!"; + + stream << "HTTP/1.1 200 OK" << newline; + stream << "Server: Ikaros" << newline; + stream << "Host: " << stringConfigs[CONFIG_STRING_HOSTNAME] << newline; + stream << "Connection: close" << newline; + stream << "Content-Length: " << str.length() << newline; + stream << "Content-Type: text/html" << newline ; + stream << newline ; + stream << str; + + socket->Send(stream); +} diff --git a/Protocol/HTTP/HTTP.h b/Protocol/HTTP/HTTP.h new file mode 100644 index 0000000..6e25ba4 --- /dev/null +++ b/Protocol/HTTP/HTTP.h @@ -0,0 +1,73 @@ +#include "Includes.cpp" +#include "Adds.h" +#include "defines.h" + +#include "ConfigMgr.cpp" + +#ifdef __cplusplus +extern "C" +{ +#endif + +void processRecieve(in_addr /* address */, int fd, char* data); +void Init(); +void InitStrings(); +void InitErrorPages(); +void LoadConfig(); + +class HTTPResponse +{ + public: + static void SendErrorPage(Socket* socket, uint32 ErrorId); + static void SendDirectPage(Socket* socket, string file); + static void SendHeadPage(Socket* socket, string file); + static void KillSpartans(Socket* socket); +}; + +#ifdef __cplusplus +} +#endif + +struct SeparateThreadedSendingData +{ + SeparateThreadedSendingData(Socket* s, const char* d, size_t l): sock(s), data(d), length(l), dat(NULL), stream(NULL) { } + SeparateThreadedSendingData(Socket* s, BinnaryData* d): sock(s), data(NULL), length(0), dat(d), stream(NULL) { } + SeparateThreadedSendingData(Socket* s, stringstream* d): sock(s), data(NULL), length(0), dat(NULL), stream(d) { } + Socket* sock; + const char* data; + size_t length; + BinnaryData* dat; + stringstream* stream; +}; + +std::map errorStrings; +std::map errorPages; +ConfigMgr* configMgr; +SimpleLog* protoLog; + +enum BoolConfigs +{ + CONFIG_BOOL_ALLOW_DEFAULT_INDEX, + CONFIG_BOOL_DEBUG, + CONFIG_BOOL_CONTROL, + MAX_BOOL_CONFIGS +}; + +enum StringConfigs +{ + CONFIG_STRING_DEFAULT_INDEX_FILE, + CONFIG_STRING_HOSTNAME, + CONFIG_STRING_ROOT_DIR, + MAX_STRING_CONFIGS +}; + +enum IntConfigs +{ + CONFIG_INT_MAX_MAIN_THREAD_FILE_SIZE, + MAX_INT_CONFIGS +}; + +bool boolConfigs[MAX_BOOL_CONFIGS]; +string stringConfigs[MAX_STRING_CONFIGS]; +int intConfigs[MAX_STRING_CONFIGS]; + diff --git a/Protocol/HTTP/defines.h b/Protocol/HTTP/defines.h new file mode 100644 index 0000000..8dd217a --- /dev/null +++ b/Protocol/HTTP/defines.h @@ -0,0 +1,11 @@ + +#ifndef __Defs +#define __Defs + +#define newline "\r\n" + +typedef unsigned char Byte; +typedef unsigned char BYTE; +typedef unsigned char byte; + +#endif // __Defs diff --git a/Protocol/HTTP/http.conf b/Protocol/HTTP/http.conf new file mode 100644 index 0000000..19d5f75 --- /dev/null +++ b/Protocol/HTTP/http.conf @@ -0,0 +1,24 @@ +# RootDirectory -- string value +# sets directory root +RootDirectory = /var/www/ + +# Debug -- bool value +# sets protocol debug output +# 0 -- disabled +# 1 -- enabled +Debug = 1 + +# Control -- bool value +# sets protocol control output +# 0 -- disabled +# 1 -- enabled +Control = 0 + +# Hostname -- string value +# sets protocol/application Hostname +Hostname = Ikaros + +# MaximalMainThreadFileSize -- int value +# sets maximal http response size for main threaded sending +# when size of response exceed this value response will be sent over separate thread +MaximalMainThreadFileSize = 40000 diff --git a/Protocol/Includes.cpp b/Protocol/Includes.cpp new file mode 100644 index 0000000..c1d70b2 --- /dev/null +++ b/Protocol/Includes.cpp @@ -0,0 +1,23 @@ +#ifndef __PCH +#define __PCH + +#include +#include +#include +#include +#include +#include +#include +#include +#include "file.h" +#include "binData.h" +#include "Application.h" +#include "Socket.h" +#include "SimpleLog.h" + +extern Application* app; + +using namespace std; + +#endif // __PCH + diff --git a/Protocol/SMTP/Adds.cpp b/Protocol/SMTP/Adds.cpp new file mode 100644 index 0000000..b14fdfa --- /dev/null +++ b/Protocol/SMTP/Adds.cpp @@ -0,0 +1,23 @@ +#include "Adds.h" +#include + + +string lower(string in) +{ + string out = in; + for (uint32 i = 0; i< in.length();i++) + if (out[i] >= 'A' && out[i] <= 'Z') + out[i] = out[i] + 32; + return out; +} + +string trim(string in) +{ + size_t pos = in.find_first_not_of(" \r\n\t"); + in.erase(0, pos ); + pos = in.find_last_not_of(" \r\n\t"); + if (pos == string::npos) + return in; + in.erase(pos + 1, string::npos); + return in; +} diff --git a/Protocol/SMTP/Adds.h b/Protocol/SMTP/Adds.h new file mode 100644 index 0000000..92982fe --- /dev/null +++ b/Protocol/SMTP/Adds.h @@ -0,0 +1,10 @@ +#include "Includes.cpp" + + +#ifndef __Adds +#define __Adds + + +int FileExists(string file); + +#endif // __Adds diff --git a/Protocol/SMTP/Base.cpp b/Protocol/SMTP/Base.cpp new file mode 100755 index 0000000..8e0056e --- /dev/null +++ b/Protocol/SMTP/Base.cpp @@ -0,0 +1,148 @@ +#include "Base.h" + + +void InitMessages(); +void LoadConfigs(); + +void Init() +{ + configMgr = new ConfigMgr("smtp.conf", NULL, 0); + protoLog = new SimpleLog(Control, Debug, "Protocol.log"); + InitMessages(); + LoadConfigs(); +} + +void InitMessages() +{ + // Connect + responseCodeMessage.insert( make_pair(220, "Welcome to Ikaros SMTP Server")); + responseCodeMessage.insert( make_pair(421, "Service not avaliable, closing transmission channel")); + // EHLO + responseCodeMessage.insert( make_pair(550, "Not Implemented")); + + responseCodeMessage.insert( make_pair(250, "Ok")); + responseCodeMessage.insert( make_pair(354, "Start mail input; end with .")); +} + +void LoadConfigs() +{ + stringConfigs[CONFIG_STRING_GREETINGS] = configMgr->LoadStringConfig("Greetings", "Welcome to Ikaros SMTP Server"); + protoLog->outDebug("CONFIG_STRING_GREETINGS= '%s'", stringConfigs[CONFIG_STRING_GREETINGS].c_str()); + protoLog->outDebug(); +} + +void processConnect(in_addr /* address */, int fd) +{ + Socket* sock = app->socketMgr->GetSocketByFd(fd); + SMTP::SendGreetings(sock); + if (sessionStatus.find(fd) == sessionStatus.end()) + sessionStatus.insert(make_pair(fd, SMTP_GREETINGS)); + sessionStatus[fd] = SMTP_HELLO; +} + + +void processDisconnect(in_addr /* address */, int fd) +{ + if (sessionStatus.find(fd) != sessionStatus.end()) + sessionStatus.erase(fd); + if (sessionData.find(fd) != sessionData.end()) + sessionData.erase(fd); + protoLog->outControl("Connection form %d closed", fd); +} + +void processRecieve(in_addr /* address */, int fd, char* data) +{ + Socket* sock = app->socketMgr->GetSocketByFd(fd); + BinnaryData dat(data, strlen(data)); + + string strdata = dat.TextLike(); + if (sessionStatus[fd] != SMTP_MAIL_DATA) + { + strdata = trim(data); + string command; // Command is four character string + dat >> command; + command = trim(command); + if (lower(command).compare("helo") == 0) + sessionStatus[fd] = SMTP_HELLO; + + if (lower(command).compare("mail") == 0) + sessionStatus[fd] = SMTP_MAIL_FROM; + + if (lower(command).compare("rcpt") == 0) + sessionStatus[fd] = SMTP_MAIL_RCPT; + + if (lower(command).compare("data") == 0) + sessionStatus[fd] = SMTP_MAIL_DATA_START; + + if (lower(command).compare("quit") == 0) + sessionStatus[fd] = SMTP_QUIT; + + protoLog->outControl("Recieved Command: '%s' Data Length: %u Data: '%s'", trim(command).c_str(), dat.size(), strdata.c_str()); + } + + + switch (sessionStatus[fd]) + { + case SMTP_GREETINGS: // Newly Connected handled in processConnect + break; + case SMTP_HELLO: + { + string name; + dat >> name; + protoLog->outDebug("Recieved Hello name: %s", name.c_str()); + sessionData[fd].Host = name; + SMTP::SendHelloResponse(sock, name); + break; + } + case SMTP_MAIL_FROM: + { + string commandData; + dat >> commandData; + commandData = trim(commandData); + string mailAddr = commandData.substr(commandData.find_first_of('<')+1, commandData.find_last_of('>') - commandData.find_first_of('<')-1); + protoLog->outDebug("Sending mail from: %s", mailAddr.c_str()); + sessionData[fd].mailFrom = mailAddr; + SMTP::SendCommandResponse(sock, 250); + break; + } + case SMTP_MAIL_RCPT: + { + string commandData; + dat >> commandData; + commandData = trim(commandData); + string mailAddr = commandData.substr(commandData.find_first_of('<')+1, commandData.find_last_of('>') - commandData.find_first_of('<')-1); + protoLog->outDebug("Sending mail To: %s", mailAddr.c_str()); + sessionData[fd].mailTo.push_back(mailAddr); + SMTP::SendCommandResponse(sock, 250); + break; + } + case SMTP_MAIL_DATA_START: + { + SMTP::SendCommandResponse(sock, 354); + sessionStatus[fd] = SMTP_MAIL_DATA; + break; + } + case SMTP_MAIL_DATA: + { + sessionData[fd].data += data; + if (sessionData[fd].data.find("\r\n.\r\n") != string::npos) + { + sessionStatus[fd] = SMTP_GREETINGS; + Files::AsciiFile file(sessionData[fd].mailTo[0]); + file.writeFile(sessionData[fd].data); + file.SaveToFile(); + sessionData[fd].data.clear(); + sessionData[fd].mailTo.clear(); + SMTP::SendCommandResponse(sock, 250); + } + break; + } + + case SMTP_QUIT: // Client quit + app->socketMgr->CloseSocketByFd(fd); + break; + default: + SMTP::SendCommandResponse(sock, 550); + break; + } +} diff --git a/Protocol/SMTP/Base.h b/Protocol/SMTP/Base.h new file mode 100644 index 0000000..ca2d038 --- /dev/null +++ b/Protocol/SMTP/Base.h @@ -0,0 +1,46 @@ +#include "Includes.cpp" +#include "SMTP.cpp" +#include "Adds.cpp" + +#include "defines.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +void processRecieve(in_addr /* address */, int fd, char* data); +void processConnect(in_addr /* address */, int fd); +void processDisconnect(in_addr /* address */, int fd); +void Init(); + + + +#ifdef __cplusplus +} +#endif + +enum SMTPStates +{ + SMTP_GREETINGS = 0, + SMTP_HELLO = 1, + SMTP_MAIL_FROM = 2, + SMTP_MAIL_RCPT = 3, + SMTP_MAIL_DATA_START = 4, + SMTP_MAIL_DATA = 5, + SMTP_QUIT = 6, + SMTP_EHLO = 7, +}; + +struct SMTPSessionData +{ + string Host; + string mailFrom; + std::vector mailTo; + string data; +}; + +std::map sessionStatus; +std::map sessionData; + diff --git a/Protocol/SMTP/CMakeLists.txt b/Protocol/SMTP/CMakeLists.txt new file mode 100644 index 0000000..ab6ae75 --- /dev/null +++ b/Protocol/SMTP/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 2.6) + +set (LibraryName SMTP) +set (ConfigName smtp.conf) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +add_library(${LibraryName} SHARED Base.cpp) +install(TARGETS ${LibraryName} DESTINATION ${InstallDirectory}) + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") + if (NOT EXISTS "${InstallDirectory}${ConfigName}") + install(FILES ${ConfigName} DESTINATION ${InstallDirectory}) + endif (NOT EXISTS "${InstallDirectory}${ConfigName}") +endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ConfigName}") diff --git a/Protocol/SMTP/SMTP.cpp b/Protocol/SMTP/SMTP.cpp new file mode 100644 index 0000000..ba167ef --- /dev/null +++ b/Protocol/SMTP/SMTP.cpp @@ -0,0 +1,25 @@ +#include "SMTP.h" + + +void SMTP::SendGreetings(Socket* sock) +{ + stringstream stream; + stream << "220 Server-Ikaros " << Greetings << newline; + sock->Send(stream); +} + +void SMTP::SendHelloResponse(Socket* sock, std::string name) +{ + stringstream stream; + stream << "250 Hello "<< name << newline; + sock->Send(stream); +} + +void SMTP::SendCommandResponse(Socket* sock, int responseCode) +{ + if (responseCodeMessage.find(responseCode) == responseCodeMessage.end()) + return; + stringstream stream; + stream << responseCode << ' ' << responseCodeMessage[responseCode] << newline; + sock->Send(stream); +} diff --git a/Protocol/SMTP/SMTP.h b/Protocol/SMTP/SMTP.h new file mode 100644 index 0000000..6acb622 --- /dev/null +++ b/Protocol/SMTP/SMTP.h @@ -0,0 +1,38 @@ +#include "Includes.cpp" +#include "defines.h" + +#include "ConfigMgr.cpp" + +std::map responseCodeMessage; + +#define Greetings "Welcome to Ikaros SMTP Server" + +bool Debug= true, Control= true; +SimpleLog* protoLog; +ConfigMgr* configMgr; + +#ifdef __cplusplus +extern "C" +{ +#endif + +class SMTP +{ + public: + static void SendGreetings(Socket* sock); + static void SendHelloResponse(Socket* sock, std::string); + static void SendCommandResponse(Socket* sock, int responseCode); + +}; + +#ifdef __cplusplus +} +#endif + +enum StringConfigs +{ + CONFIG_STRING_GREETINGS, + MAX_STRING_CONFIGS +}; + +string stringConfigs[MAX_STRING_CONFIGS]; diff --git a/Protocol/SMTP/defines.h b/Protocol/SMTP/defines.h new file mode 100644 index 0000000..c26f6ed --- /dev/null +++ b/Protocol/SMTP/defines.h @@ -0,0 +1,14 @@ +#ifndef __Defs +#define __Defs + +#define newline "\r\n" + + +typedef unsigned char Byte; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned int uint32; +typedef unsigned short uint16; + + +#endif // __Defs diff --git a/Protocol/SMTP/smtp.conf b/Protocol/SMTP/smtp.conf new file mode 100644 index 0000000..644a96e --- /dev/null +++ b/Protocol/SMTP/smtp.conf @@ -0,0 +1,3 @@ +# Greetings -- string value +# sets message to be sent when client connects +Greetings= Welcome to Ikaros, multifunctional server based SMTP diff --git a/Protocol/libdump/CMakeLists.txt b/Protocol/libdump/CMakeLists.txt new file mode 100644 index 0000000..babc11b --- /dev/null +++ b/Protocol/libdump/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required (VERSION 2.6) + +set (LibraryName dump) + + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +add_library(${LibraryName} SHARED libdump.cpp) +install(TARGETS ${LibraryName} DESTINATION ${InstallDirectory}) diff --git a/Protocol/libdump/libdump.cpp b/Protocol/libdump/libdump.cpp new file mode 100644 index 0000000..c682a64 --- /dev/null +++ b/Protocol/libdump/libdump.cpp @@ -0,0 +1,9 @@ +#include "libdump.h" +#include +using std::cout; +using std::endl; + +void Recieve(char* data) +{ +cout<("Library is not opened"); + return NULL ; + } + void * func = dlsym(lib_handle,Func); + if (!func) + { + char* buf = dlerror(); + if (lastErr) + delete lastErr; + lastErr = new char[strlen(buf)]; + strcpy(lastErr, buf); + return NULL; + } + return func ; +} + +void SharedLibrary::close() +{ + if(isopen) + dlclose(lib_handle); +} diff --git a/Shared/Shared.h b/Shared/Shared.h new file mode 100644 index 0000000..113fb10 --- /dev/null +++ b/Shared/Shared.h @@ -0,0 +1,35 @@ +#include +#include + +#ifndef __Shared +#define __Shared + +// COMPILE Using -ldl -rdynamic +#ifndef NULL + #define NULL 0 +#endif + +class SharedLibrary +{ + public: + SharedLibrary(): LibName(NULL), lastErr(NULL), lib_handle(NULL), isopen(false) { } + SharedLibrary(const char* Lib): LibName(NULL), lastErr(NULL), lib_handle(NULL), isopen(false) { open(Lib); } + ~SharedLibrary() { close(); } + + bool open(const char* LibLink); + inline bool is_open() const { return isopen; } + void close(); + + void* findFunc(const char* Func); + + inline char* getError() const { return lastErr; } + inline const char* GetLibraryPath() const { return LibName; } + + protected: + const char *LibName ; + char *lastErr ; + void *lib_handle ; + bool isopen ; + +}; +#endif diff --git a/Signal/SignalHandler.cpp b/Signal/SignalHandler.cpp new file mode 100644 index 0000000..ff6e050 --- /dev/null +++ b/Signal/SignalHandler.cpp @@ -0,0 +1,121 @@ +#include "SignalHandler.h" + +void SignalHandler::setSignalHandler(SignalType sig ,SignalFunction func ) +{ + assert(func); + switch(sig) + { + case Abort: + fSIGABRT = func ; + signal(Abort,fSIGABRT); + break; + + case FloatingPointException: + fSIGFPE = func ; + signal(FloatingPointException,fSIGFPE); + break; + + case InvalidInstruction: + fSIGILL = func ; + signal(InvalidInstruction,fSIGILL); + break; + + case Interupt: + fSIGINT = func ; + signal(Interupt,fSIGINT); + break; + + case SegmentationFault: + fSIGSEGV = func ; + signal(SegmentationFault,fSIGSEGV ); + break; + + case Terminate: + fSIGTERM = func ; + signal(Terminate,fSIGTERM); + break; + + case Continue: + fSIGCONT = func ; + signal(Continue,fSIGCONT); + break; + + default: + break; + } + +} + +void SignalHandler::setIgnoreSignal(SignalType sig) +{ + switch(sig) + { + case Abort: + signal(Abort,SIG_IGN); + break; + + case FloatingPointException: + signal(FloatingPointException,SIG_IGN); + break; + + case InvalidInstruction: + signal(InvalidInstruction,SIG_IGN); + break; + + case Interupt: + signal(Interupt,SIG_IGN); + break; + + case SegmentationFault: + signal(SegmentationFault,SIG_IGN); + break; + + case Terminate: + signal(Terminate,SIG_IGN); + break; + + case Continue: + signal(Continue,SIG_IGN); + break; + + default: + break; + } +} + +void SignalHandler::setDefaultHandler(SignalType sig) +{ + switch(sig) + { + case Abort: + signal(Abort,SIG_DFL); + break; + + case FloatingPointException: + signal(FloatingPointException,SIG_DFL); + break; + + case InvalidInstruction: + signal(InvalidInstruction,SIG_DFL); + break; + + case Interupt: + signal(Interupt,SIG_DFL); + break; + + case SegmentationFault: + signal(SegmentationFault,SIG_DFL); + break; + + case Terminate: + signal(Terminate,SIG_DFL); + break; + + case Continue: + signal(Continue,SIG_DFL); + break; + + default: + break; + } +} diff --git a/Signal/SignalHandler.h b/Signal/SignalHandler.h new file mode 100644 index 0000000..baf55fe --- /dev/null +++ b/Signal/SignalHandler.h @@ -0,0 +1,36 @@ +#include +#include + +#ifndef __Signal +#define __Signal + +enum SignalType +{ + Abort = SIGABRT , + FloatingPointException = SIGFPE , + InvalidInstruction = SIGILL , + Interupt = SIGINT , + SegmentationFault = SIGSEGV , + Terminate = SIGTERM , + Continue = SIGCONT +}; + +class SignalHandler +{ + public: + + typedef void (*SignalFunction)(int p) ; + SignalFunction fSIGABRT ; + SignalFunction fSIGFPE ; + SignalFunction fSIGILL ; + SignalFunction fSIGINT ; + SignalFunction fSIGSEGV ; + SignalFunction fSIGTERM ; + SignalFunction fSIGCONT ; + + void setSignalHandler(SignalType sig, SignalFunction func); + void setIgnoreSignal(SignalType sig); + void setDefaultHandler(SignalType sig); +}; + +#endif diff --git a/SimpleLog/SimpleLog.cpp b/SimpleLog/SimpleLog.cpp new file mode 100644 index 0000000..47b67b8 --- /dev/null +++ b/SimpleLog/SimpleLog.cpp @@ -0,0 +1,173 @@ +#include "SimpleLog.h" + + +SimpleLog::SimpleLog(bool &C, bool &D, const char* logfile): +logf(NULL), mdate(NULL), Debug(D), Control(C) +{ + if (logfile) + { + logf = logfile; + fclose(fopen(logf, "w")); + } + mdate= new char[256]; + pthread_mutex_init(&writeMutex, NULL); +} + +SimpleLog::~SimpleLog() +{ + if (mdate) + delete mdate; + pthread_mutex_destroy(&writeMutex); +} + +int SimpleLog::outControl(const char* format, ...) +{ + if (Control) + { + pthread_mutex_lock(&writeMutex); + va_list arg; + int done = 0; + if (strlen(format)) + { + memset(mdate, 0, 256); + time(&d); + strftime(mdate, 256, "%Y-%m-%d %H:%M:%S", localtime(&d)); + printf("%s \t", mdate); + va_start(arg, format); + done = vfprintf(stdout, format, arg); + va_end(arg); + } + if (logf) + { + FILE* log = fopen(logf, "a"); + assert(log); + if (strlen(format)) + { + va_start(arg, format); + fprintf(log,"%s \t", mdate); + vfprintf(log, format, arg); + va_end(arg); + } + fclose(log); + } + std::cout << std::endl ; + std::cout.flush(); + pthread_mutex_unlock(&writeMutex); + return done; + } + else + return 0; +} + +int SimpleLog::outString(const char* format, ...) +{ + va_list arg; + int done = 0; + pthread_mutex_lock(&writeMutex); + if (strlen(format)) + { + memset(mdate, 0, 256); + time(&d); + strftime(mdate, 256, "%Y-%m-%d %H:%M:%S", localtime(&d)); + printf("%s \t", mdate); + va_start(arg, format); + done = vfprintf(stdout, format, arg); + va_end(arg); + } + + if (logf) + { + FILE* log = fopen(logf, "a"); + assert(log); + if (strlen(format)) + { + va_start(arg, format); + fprintf(log,"%s \t", mdate); + vfprintf(log, format, arg); + va_end(arg); + } + fprintf(log, "\n"); + fclose(log); + } + std::cout << std::endl ; + std::cout.flush(); + pthread_mutex_unlock(&writeMutex); + return done; +} + +int SimpleLog::outDebug(const char* format, ...) +{ + if (Debug) + { + pthread_mutex_lock(&writeMutex); + va_list arg; + int done = 0; + if (strlen(format)) + { + memset(mdate, 0, 256); + time(&d); + strftime(mdate, 256, "%Y-%m-%d %H:%M:%S", localtime(&d)); + printf("%s \t", mdate); + va_start(arg, format); + done = vfprintf(stdout, format, arg); + va_end(arg); + } + if (logf) + { + FILE* log = fopen(logf,"a"); + assert(log); + if (strlen(format)) + { + va_start(arg, format); + fprintf(log,"%s \t",mdate); + vfprintf(log, format, arg); + va_end(arg); + } + fprintf(log,"\n"); + fclose(log); + } + va_end (arg); + std::cout << std::endl ; + std::cout.flush(); + pthread_mutex_unlock(&writeMutex); + return done; + } + else + return 0; +} + +int SimpleLog::outError(const char* format, ...) +{ + va_list arg; + int done = 0; + pthread_mutex_lock(&writeMutex); + if (strlen(format)) + { + memset(mdate, 0, 200); + time(&d); + strftime(mdate, 256, "%Y-%m-%d %H:%M:%S", localtime(&d)); + printf("%s \t[ERROR] ", mdate); + va_start(arg, format); + done = vfprintf(stdout, format, arg); + va_end(arg); + } + if (logf) + { + FILE* log = fopen(logf, "a"); + assert(log); + if (strlen(format)) + { + va_start(arg, format); + fprintf(log, "%s \t", mdate); + fprintf(log, "[ERROR] "); + vfprintf(log, format, arg); + va_end(arg); + } + fprintf(log,"\n"); + fclose(log); + } + std::cout << std::endl ; + std::cout.flush(); + pthread_mutex_unlock(&writeMutex); + return done; +} diff --git a/SimpleLog/SimpleLog.h b/SimpleLog/SimpleLog.h new file mode 100644 index 0000000..b2658c3 --- /dev/null +++ b/SimpleLog/SimpleLog.h @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +#include // for Mutex (compile with -pthread) + +#ifndef __SimpleLog +#define __SimpleLog + +using std::endl ; +using std::cout ; + +class SimpleLog +{ + public: + SimpleLog(bool &C, bool &D, const char* logfile = NULL); + ~SimpleLog(); + int outString(const char* format = "", ...); + int outControl(const char* format = "", ...); + int outDebug(const char* format = "", ...); + int outError(const char* format = "", ...); + + private: + const char* logf ; + char* mdate; + time_t d ; + bool &Debug; + bool &Control; + pthread_mutex_t writeMutex; +}; + +#endif diff --git a/Sockets/Socket.cpp b/Sockets/Socket.cpp new file mode 100644 index 0000000..ddb22b5 --- /dev/null +++ b/Sockets/Socket.cpp @@ -0,0 +1,233 @@ +#include "Socket.h" + + +Socket::~Socket() +{ + Close(); +} + +int Socket::Close() +{ + if (socket && isConnected) + return close(socket); + return 0; +} + +int Socket::Send(const void* buffer, size_t len, int flags) +{ + size_t sended = 0; + int ret = 0; + while (len > sended) + { + if (!this || socket < 0) + return -1; + #pragma GCC diagnostic ignored "-Wpointer-arith" + ret = send(socket, (const void*) (buffer + sended), len - sended, flags); + #pragma GCC diagnostic warning "-Wpointer-arith" + if (ret > 0) + { + sended += ret; + //printf("\n\nSending %lu bytes (Already Sended: %lu bytes %f%) ret: %d errno %d\n\n", len, sended, sended * 100.f/ float(len), ret, errno); + } + else if (ret == 0) + { + isConnected = false; + error = errno; + return ret; + } + else if (ret == -1) + { + error = errno; + switch (error) + { + case EAGAIN: + break; + default: + return ret; + } + } + } + return sended; +} + +int Socket::Send(BinnaryData &data, int flags) +{ + return Send(data, data.size(), flags); +} + +int Socket::Recieve(void* buffer, size_t len, int flags) +{ + int ret = 0; + ret = recv(socket, buffer, len, flags); + if (ret == 0) + { + isConnected = false; + error = errno; + } + if (ret == -1) + error = errno; + return ret; +} + +int Socket::Recieve(BinnaryData &data, int flags) +{ + return Recieve(data, data.capacity(), flags); +} + + +bool _isIPv4(char* ip) +{ + int Byte[4]; + short pos[5]={-1, 0 ,0, 0, 0}; + if (strlen(ip) - 1 < 7) + return false; + if (strlen(ip) - 1 > 15) + return false; + ushort i = 0; + ushort dotc=0; + + while(i != strlen(ip) - 1) + { + if (*(ip+i) == '.') + dotc++; + i++; + } + + if (dotc != 3) + return false ; + for (uint i = 0, posc = 1; i < strlen(ip) - 1; i++) + { + if (*(ip + i) == '.') + { + if(posc == 5) + return false; + pos[posc] = i; + + if (abs(pos[posc - 1] - pos[posc]) - 1 > 3) + return false; + Byte[posc]= atoi(ip + pos[posc] + 1); + posc++; + } + } + Byte[0] = atoi(ip); + + for (ushort i = 0; i < 4; i++) + { + if (Byte[i] < 0 || Byte[i] > 255) + return false; + } + return true; +} + + +int TCPSocket::Send(const char *buff, unsigned short length, unsigned char flags) +{ + int ret = send(sock, buff, length, flags); + isConnected = !(ret == 0); + return ret; +} + +int TCPSocket::Recv(char *buff, unsigned short length, unsigned char flags) +{ + int ret = recv(sock, buff, length, flags); + isConnected = !(ret == 0); + return ret; +} + +int TCPSocket::Connect(char* Ip) +{ + char* port = strchr(Ip, ':') + 1 ; + char ip[strlen(Ip) + 5]; + memset(ip, 0, strlen(Ip) + 5); + strcpy(ip, Ip); + *((char*) strrchr(ip, ':')) = '\0'; + if (_isIPv4(ip)) + return Connect(ip, port); + else + return DNSConnect(ip, port); +} + +int TCPSocket::Connect(char *IPAdress, char *Port) +{ + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(atoi(Port)); + dest.sin_addr.s_addr = inet_addr(IPAdress); + if (_isIPv4(IPAdress)) + { + int ret = connect(sock, (struct sockaddr*)&dest, sizeof(dest)); + isConnected = (ret == 0); + return ret; + } + else + return DNSConnect(IPAdress, Port); +} + +int TCPSocket::Connect(unsigned int IPAdress, unsigned short Port) +{ + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = Port; + dest.sin_addr.s_addr = IPAdress; + + int ret = connect(sock, (struct sockaddr*)&dest, sizeof(dest)); + isConnected = (ret == 0); + return ret; +} + +int TCPSocket::Connect(char* IPAdress, unsigned short Port) +{ + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(Port); + dest.sin_addr.s_addr = inet_addr(IPAdress); + if (_isIPv4(IPAdress)) + { + int ret = connect(sock, (struct sockaddr*)&dest, sizeof(dest)); + isConnected = (ret == 0); + return ret; + } + else + return DNSConnect(IPAdress, Port); +} + +int TCPSocket::DNSConnect(char *DomainName, char *Port) +{ + struct hostent* host ; + host = gethostbyname(DomainName); + + if (!host) + return -1 ; + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(atoi(Port)); + dest.sin_addr.s_addr= *((unsigned long *) host->h_addr_list[0]); + + int ret = connect(sock, (struct sockaddr*)&dest, sizeof(dest)); + isConnected = (ret == 0); + return ret; +} + +int TCPSocket::DNSConnect(char *DomainName, unsigned short Port) +{ + struct hostent* host ; + host = gethostbyname(DomainName); + + bzero(&dest, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(Port); + dest.sin_addr.s_addr= *((unsigned long *) host->h_addr_list[0]); + + int ret = connect(sock, (struct sockaddr*)&dest, sizeof(dest)); + isConnected = (ret == 0); + return ret; +} + +TCPSocket::TCPSocket() +{ + sock = socket(AF_INET, SOCK_STREAM, 0); +} + +TCPSocket::~TCPSocket() +{ +} diff --git a/Sockets/Socket.h b/Sockets/Socket.h new file mode 100644 index 0000000..051ff31 --- /dev/null +++ b/Sockets/Socket.h @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include // sprintf etc +#include // sprintf etc + +#include +#include +#include // for atoi() +#include // For errno + +#include "file.h" + +#ifndef __SOCKET +#define __SOCKET + +class Socket +{ + public: + Socket(int sock, sockaddr_in addr): socket(sock), address(addr) { isConnected = true; } + Socket(int sock): socket(sock) { isConnected = true; } + ~Socket(); + + int Send(const void* buffer, size_t len, int flags = 0); + int Send(BinnaryData &data, int flags = 0); + int Send(std::stringstream &data, int flags = 0) { return Send(data.str().c_str(), data.str().length(), flags); } + + int Recieve(void* buffer, size_t len, int flags = 0); + int Recieve(BinnaryData &data, int flags = 0); + + int Close(); + inline const char* GetAddress()const { return inet_ntoa(address.sin_addr); } + inline sockaddr_in GetAddr() const { return address; } + + inline int errnum() const { return error; } + inline bool is_connected() const { return isConnected; } + operator int() { return socket; } + inline int GetFD() const { return socket; } + + private: + int socket; + int error; + bool isConnected; + sockaddr_in address; +}; + +bool _isIPv4(char* ip); + +class TCPSocket +{ + public: + int sock ; + + public: + int Send(const char* buff, unsigned short length, unsigned char flags); + int Recv(char* buff, unsigned short length, unsigned char flags); + + int DNSConnect(char* DomainName, char* Port); + int DNSConnect(char* DomainName, unsigned short Port); + + int Connect(char* IPAdress, char* Port); + int Connect(char* Ip, unsigned short Port); + int Connect(unsigned int IPAdress, unsigned short Port); + int Connect(char* Ip); + + int setSockOpt(int level, int option_name, const void *option_value, socklen_t option_len) + { + return setsockopt(sock,level,option_name,option_value,option_len); + } + bool Connected() const { return isConnected; } + + void Close() { close(sock); } + void Disconnect() { Close(); } + TCPSocket(); + TCPSocket(int socket): sock(socket) { } + ~TCPSocket(); + + private: + struct sockaddr_in dest; + bool isConnected; +}; + +#endif diff --git a/Sockets/SocketMgr.cpp b/Sockets/SocketMgr.cpp new file mode 100644 index 0000000..e79a882 --- /dev/null +++ b/Sockets/SocketMgr.cpp @@ -0,0 +1,115 @@ +#include "SocketMgr.h" + +ConnectionMgr::~ConnectionMgr() +{ + CloseAllSockets(); +} + +void ConnectionMgr::CloseAllSockets() +{ + while (sockets.size()) + { + SocketMap::iterator it = sockets.begin(); + it->second->Close(); + sockets.erase(it); + } +} + +void ConnectionMgr::CloseAllPendingSockets() +{ + while (queue.size()) + { + queue.front()->second->Close(); + sockets.erase(queue.front()); + queue.pop(); + } +} + +Socket* ConnectionMgr::AddSocket(Socket* sock) +{ + if (sockets.find(sock->GetFD()) != sockets.end()) + return sock; + + sockets.insert(std::pair(sock->GetFD(), sock)); + return sock; +} + +void ConnectionMgr::CloseSocketById(uint32 id) +{ + if (id > sockets.size()) + return; + + SocketMap::iterator sock = GetSocketMapElementById(id); + if (sock == sockets.end()) + return; + + if (closeImmediatly) + { + sock->second->Close(); + sockets.erase(sock); + } + else + queue.push(sock); +} + +void ConnectionMgr::CloseSocketByFd(int fd) +{ + SocketMap::iterator sock = sockets.find(fd); + if (sock == sockets.end()) + return; + + if (closeImmediatly) + { + sock->second->Close(); + sockets.erase(sock); + } + else + queue.push(sock); +} + +void ConnectionMgr::CloseSocket(SocketMap::iterator sock) +{ + if (closeImmediatly) + { + sock->second->Close(); + sockets.erase(sock); + } + else + queue.push(sock); +} + +Socket* ConnectionMgr::GetSocketById(uint32 id) +{ + if (id > sockets.size()) + return sockets.begin()->second; + SocketMap::iterator sock = GetSocketMapElementById(id); + + return sock->second; +} + +Socket* ConnectionMgr::GetSocketByFd(int fd) +{ + SocketMap::iterator it = sockets.find(fd); + if (it != sockets.end()) + { + return it->second; + } + return NULL; +} + +ConnectionMgr::SocketMap::iterator ConnectionMgr::GetSocketMapElementById(uint32 id) +{ + if (id > sockets.size()) + return sockets.end(); + SocketMap::iterator it = sockets.begin(); + advance(it,id); + return it; +} + +int ConnectionMgr::GetHighestFd() +{ + if (sockets.size() == 0) + return 0; + + return GetSocketMapElementById(sockets.size()-1)->second->GetFD(); +} diff --git a/Sockets/SocketMgr.h b/Sockets/SocketMgr.h new file mode 100644 index 0000000..f5447f2 --- /dev/null +++ b/Sockets/SocketMgr.h @@ -0,0 +1,45 @@ +#include +#include + +#include "Socket.h" + +using std::map; +using std::queue; + +#ifndef __SOCKET_MGR +#define __SOCKET_MGR + +class ConnectionMgr +{ + public: + typedef std::map SocketMap; + typedef std::queue CloseQueue; + + + ConnectionMgr(): closeImmediatly(false) { sockets.clear(); } + ~ConnectionMgr(); + + Socket* AddSocket(Socket* sock); + + void CloseSocketById(uint32 sock); + void CloseSocketByFd(int fd); + void CloseSocket(SocketMap::iterator sock); + void CloseAllSockets(); + void CloseAllPendingSockets(); + + Socket* GetSocketById(uint32 sock); + SocketMap::iterator GetSocketMapElementById(uint32 id); + Socket* GetSocketByFd(int fd); + + int GetHighestFd(); + inline int ConnectionsCount() const { return sockets.size(); } + + bool CanCloseImmediatly(bool s) { return closeImmediatly = s; } + + SocketMap sockets; + CloseQueue queue; + protected: + bool closeImmediatly; +}; + +#endif diff --git a/Threads/ThreadMgr.cpp b/Threads/ThreadMgr.cpp new file mode 100644 index 0000000..821516c --- /dev/null +++ b/Threads/ThreadMgr.cpp @@ -0,0 +1,320 @@ +#include "ThreadMgr.h" + + +Thread* Thread::CreateThread(void * (*func)(void *), void *args) +{ + Thread* n = new Thread(); + if (pthread_create(&n->thread, NULL, func, args) == 0) + { + n->status = THREAD_ACTIVE; + n->function = func; + n->args = args; + return n ; + } + return NULL ; +} + + + +int ThreadMgr::CreateThread(void * (*func)(void *), void *args) +{ + Thread n; + if (pthread_create(&n.thread, NULL, func, args) == 0) + { + n.id = pThreads.size(); + n.status = THREAD_ACTIVE; + pThreads.push_back(n); + return pThreads.size()-1 ; + } + return -1 ; +} + +int ThreadMgr::CreateThread(string ThreadName, void * (*func)(void *), void *args) +{ + if (pThreadNames.find(ThreadName) != pThreadNames.end()) + return -1; + + int ret = CreateThread(func,args); + if (ret != -1) + { + pThreadNames.insert(std::pair(ThreadName, ret)); + return ret; + } + return -1 ; +} + + +bool ThreadMgr::CancelThread(uint32 threadId) +{ + if (threadId < pThreads.size()) + if (pthread_cancel(getThread(threadId)) == 0) + return true; + return false; +} + +bool ThreadMgr::CancelThread(string ThreadName) +{ + return CancelThread(GetThreadIdByName(ThreadName)); +} + +bool ThreadMgr::JoinThead(uint32 threadId,void** retval) +{ + if (threadId < pThreads.size()) + if (pthread_join(getThread(threadId), retval) == 0) + return true; + return false; +} + +bool ThreadMgr::JoinThead(string ThreadName,void** retval) +{ + return JoinThead(GetThreadIdByName(ThreadName), retval); +} + +list::iterator ThreadMgr::pgetThread(uint32 index) +{ + if (index > pThreads.size()) + return list::iterator() ; + list::iterator itr = pThreads.begin() ; + advance(itr, index); + return itr ; +} + +Thread& ThreadMgr::getThread(uint32 index) +{ + return *pgetThread(index) ; +} + +list::iterator ThreadMgr::pgetThread(pthread_t pthread) +{ + list::iterator itr = pThreads.begin() ; + for (; itr != pThreads.end(); itr++) + if (pthread_equal(itr->thread, pthread)) + return itr ; + return pThreads.end(); +} + +Thread& ThreadMgr::getThread(pthread_t thread) +{ + list::iterator it = pgetThread(thread); + if (it != pThreads.end()) + return *it ; + return *(Thread*)(NULL); +} + +int ThreadMgr::getThreadId(pthread_t thread) +{ + if (&getThread(thread)) + return getThread(thread).id ; + return -1; +} + +bool ThreadMgr::SendSignalToThread(uint32 ThreadId, int Signal) +{ + if (ThreadId >= pThreads.size()) + return false; + return pthread_kill(getThread(ThreadId), Signal) == 0; +} + +bool ThreadMgr::SendSignalToThread(string ThreadName, int Signal) +{ + return SendSignalToThread(GetThreadIdByName(ThreadName), Signal); +} + +uint32 ThreadMgr::GetThreadIdByName(string ThreadName) +{ + if (pThreadNames.find(ThreadName) == pThreadNames.end()) + return pThreadNames.size(); + return pThreadNames.find(ThreadName)->second; +} + +bool ThreadMgr::SetThreadName(uint32 ThreadId, string ThreadName) +{ + if (pThreadNames.find(ThreadName) != pThreadNames.end()) + return false; + pThreadNames.insert(std::pair(ThreadName, ThreadId)); + return true; +} + +int ThreadMgr::GetThreadStatus(string ThreadName) +{ + return GetThreadStatus(GetThreadIdByName(ThreadName)); +} + +int ThreadMgr::GetThreadStatus(pthread_t thread) +{ + if (getThreadId(thread) != -1) + return GetThreadStatus(uint32(getThreadId(thread))); + return 0; +} + +int ThreadMgr::GetThreadStatus(uint32 ThreadId) +{ + if (ThreadId >= pThreads.size()) + return -1; + return getThread(ThreadId).status; +} + +void ThreadMgr::SetThreadStatus(string ThreadName, int Status) +{ + SetThreadStatus(GetThreadIdByName(ThreadName), Status); +} + +void ThreadMgr::SetThreadStatus(pthread_t thread, int Status) +{ + if (getThreadId(thread) != -1) + SetThreadStatus(uint32(getThreadId(thread)), Status); +} + +void ThreadMgr::SetThreadStatus(uint32 ThreadId, int Status) +{ + if (ThreadId >= pThreads.size()) + return; + if (Status > THREAD_STATUS_BEGIN && Status < THREAD_STATUS_END) + getThread(ThreadId).status = Status; +} + +/* */ +/* Mutexes */ +/* */ +int ThreadMgr::CreateMutex(std::string MutexName, const pthread_mutexattr_t * Attr) +{ + if (pMutexes.find(MutexName) != pMutexes.end()) + return false; + int ret = 0; + pthread_mutex_t mutex; + ret = pthread_mutex_init(&mutex, Attr); + pMutexes.insert(std::pair(MutexName, mutex)); + return ret; +} + +void ThreadMgr::AddMutex(std::string MutexName, pthread_mutex_t mutex) +{ + if (pMutexes.find(MutexName) != pMutexes.end()) + return; + + pMutexes.insert(std::pair(MutexName, mutex)); +} + +int ThreadMgr::LockMutex(std::string MutexName) +{ + if (pMutexes.find(MutexName) == pMutexes.end()) + return false; + + int ret = 0; + ret = pthread_mutex_lock(&GetMutex(MutexName)); + return ret; +} + +int ThreadMgr::UnlockMutex(std::string MutexName) +{ + if (pMutexes.find(MutexName) == pMutexes.end()) + return false; + + int ret = 0; + ret = pthread_mutex_unlock(&GetMutex(MutexName)); + return ret; +} + +int ThreadMgr::TryLockMutex(std::string MutexName) +{ + if (pMutexes.find(MutexName) == pMutexes.end()) + return false; + + int ret = 0; + ret = pthread_mutex_trylock(&GetMutex(MutexName)); + return ret; +} + +int ThreadMgr::DestroyMutex(std::string MutexName) +{ + if (pMutexes.find(MutexName) == pMutexes.end()) + return false; + + int ret = 0; + MutexMap::iterator it = pMutexes.find(MutexName); + ret = pthread_mutex_destroy(&(it->second)); + pMutexes.erase(it); + return ret; +} + +pthread_mutex_t& ThreadMgr::GetMutex(std::string MutexName) +{ + if (pMutexes.find(MutexName) == pMutexes.end()) + return *(pthread_mutex_t*)NULL; + + MutexMap::iterator it = pMutexes.find(MutexName); + return it->second; +} + +bool ThreadMgr::MutexExists(std::string MutexName) +{ + if (pMutexes.find(MutexName) != pMutexes.end()) + return true; + return false; +} + +/* */ +/* Conditions */ +/* */ + +int ThreadMgr::CreateCondition(std::string ConditionName, const pthread_condattr_t * Attr) +{ + if (pConditions.find(ConditionName) != pConditions.end()) + return false; + int ret = 0; + pthread_cond_t condition; + ret = pthread_cond_init(&condition,Attr); + pConditions.insert(std::pair(ConditionName,condition)); + return ret; +} + +int ThreadMgr::ConditionWait(std::string ConditionName, std::string MutexName) +{ + if (pConditions.find(ConditionName) == pConditions.end() || pMutexes.find(MutexName) == pMutexes.end()) + return false; + + return pthread_cond_wait(&GetCondition(ConditionName),&GetMutex(MutexName)); +} + +int ThreadMgr::ConditionSignal(std::string ConditionName) +{ + if (pConditions.find(ConditionName) == pConditions.end()) + return false; + + return pthread_cond_signal(&GetCondition(ConditionName)); +} + +int ThreadMgr::ConditionBroadcast(std::string ConditionName) +{ + if (pConditions.find(ConditionName) == pConditions.end()) + return false; + + return pthread_cond_broadcast(&GetCondition(ConditionName)); +} + +pthread_cond_t& ThreadMgr::GetCondition(std::string ConditionName) +{ + if (pConditions.find(ConditionName) == pConditions.end()) + return *(pthread_cond_t*)NULL; + + ConditionMap::iterator it = pConditions.find(ConditionName); + return it->second; +} + +int ThreadMgr::DestroyCondition(std::string ConditionName) +{ + if (pConditions.find(ConditionName) == pConditions.end()) + return false; + int ret = 0; + ConditionMap::iterator it = pConditions.find(ConditionName); + ret = pthread_cond_destroy(&it->second); + pConditions.erase(it); + return ret; +} + +bool ThreadMgr::ConditionExists(std::string ConditionName) +{ + if (pConditions.find(ConditionName) != pConditions.end()) + return true; + return false; +} diff --git a/Threads/ThreadMgr.h b/Threads/ThreadMgr.h new file mode 100644 index 0000000..a407c31 --- /dev/null +++ b/Threads/ThreadMgr.h @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "Defs.h" + +#ifndef __Threads +#define __Threads + +using std::string; +using std::map; +using std::list; + +struct compStr +{ + bool operator()(const char* s1, const char* s2) const + { + return strcmp(s1, s2) < 0; + } + bool operator()(string s1, string s2) const + { + return s1.compare(s2) < 0; + } +}; + +typedef std::map MutexMap ; +typedef std::map ConditionMap ; +typedef std::map ThreadNameMap; +typedef void* (*CalledFunction)(void*); + +enum ThreadStatus +{ + THREAD_STATUS_BEGIN = 1, + THREAD_ACTIVE, + THREAD_SUSPENDED, + THREAD_EXIT, + THREAD_STATUS_END +}; + +struct Thread +{ + Thread(): id(0), status(0), attributes(0) { } + pthread_t thread; + uint32 id; + int status; + uint32 attributes; + CalledFunction function; + void* args; + + static Thread* CreateThread(void* (*func)(void*), void* args); + operator pthread_t() { return thread; } + operator int() { return id; } +}; + +class ThreadMgr +{ + public: + ThreadMgr(){ pThreads.clear(); } + ~ThreadMgr(){ pThreads.clear(); } + + int CreateThread(string ThreadName, CalledFunction func, void* args); + int CreateThread(CalledFunction func, void* args); + + bool CancelThread(uint32 ThreadId); + bool CancelThread(string ThreadName); + + bool JoinThead(uint32 ThreadId, void** retval); + bool JoinThead(string ThreadName, void** retval); + + int AddThread(string ThreadName, Thread* thread) + { + thread->id = pThreads.size(); + pThreads.push_back(*thread); + pThreadNames.insert(std::pair(ThreadName, thread->id)); + return thread->id; + } + + static bool Exit(void* retval){ pthread_exit(retval); } //This Thread!! + + bool SendSignalToThread(uint32 ThreadId, int Signal); + bool SendSignalToThread(string ThreadName, int Signal); + + bool KillThread(uint32 ThreadId) { return SendSignalToThread(ThreadId, SIGTERM); } + bool KillThread(string ThreadName) { return SendSignalToThread(GetThreadIdByName(ThreadName), SIGTERM); } + + bool ResumeThread(uint32 ThreadId) { return SendSignalToThread(ThreadId, SIGCONT); } + bool ResumeThread(string ThreadName) { return SendSignalToThread(GetThreadIdByName(ThreadName), SIGCONT); } + + uint32 GetThreadIdByName(string ThreadName); + bool SetThreadName(uint32 ThreadId, string ThreadName); + + int GetThreadStatus(string ThreadName); + int GetThreadStatus(uint32 ThreadId); + int GetThreadStatus(int ThreadId) + { + if (ThreadId >= 0 && uint32(ThreadId) < pThreads.size()) + return GetThreadStatus(uint32(ThreadId)); + return 0; + } + int GetThreadStatus(pthread_t thread); + + void SetThreadStatus(string ThreadName, int Status); + void SetThreadStatus(uint32 ThreadId, int Status); + void SetThreadStatus(pthread_t thread, int Status); + + int CreateMutex(std::string MutexName, const pthread_mutexattr_t * Attr = NULL); + static pthread_mutex_t _CreateMutex(const pthread_mutexattr_t * Attr = NULL) + { + pthread_mutex_t mutex; + pthread_mutex_init(&mutex, Attr); + return mutex; + } + void AddMutex(std::string MutexName, pthread_mutex_t mutex); + int LockMutex(std::string MutexName); + int UnlockMutex(std::string MutexName); + int TryLockMutex(std::string MutexName); + pthread_mutex_t& GetMutex(std::string MutexName); + int DestroyMutex(std::string MutexName); + bool MutexExists(std::string MutexName); + + int CreateCondition(std::string ConditionName, const pthread_condattr_t * Attr = NULL); + int ConditionWait(std::string ConditionName, std::string MutexName); + int ConditionSignal(std::string ConditionName); + int ConditionBroadcast(std::string ConditionName); + pthread_cond_t& GetCondition(std::string ConditionName); + int DestroyCondition(std::string ConditionName); + bool ConditionExists(std::string ConditionName); + + std::list::iterator pgetThread(uint32 index); + Thread& getThread(uint32 index); + + std::list::iterator pgetThread(pthread_t thread); + Thread& getThread(pthread_t thread); + int getThreadId(pthread_t thread); + + std::list pThreads ; + MutexMap pMutexes; + ConditionMap pConditions; + ThreadNameMap pThreadNames; +}; + + +inline pthread_t GetThisThread() +{ + return pthread_self(); +} +#endif diff --git a/Utilities/Utils.cpp b/Utilities/Utils.cpp new file mode 100644 index 0000000..9fcb8c9 --- /dev/null +++ b/Utilities/Utils.cpp @@ -0,0 +1,28 @@ +#include "Utils.h" + + +std::string& refTrim(std::string &s) +{ + size_t lastchar = s.find_last_not_of(' ')+1; + size_t firstchar = s.find_first_not_of(' '); + if (lastchar == string::npos && lastchar > s.length()) + lastchar = s.length(); + if (firstchar == string::npos) + firstchar = 0; + s.erase(lastchar, s.length() - lastchar); + s.erase(0, firstchar); + return s; +} + +int setNonblocking(int fd) +{ + int flags; +#if defined(O_NONBLOCK) + if (-1 == (flags = fcntl(fd, F_GETFL, 0))) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#else + flags = 1; + return ioctl(fd, FIOBIO, &flags); +#endif +} diff --git a/Utilities/Utils.h b/Utilities/Utils.h new file mode 100644 index 0000000..edb3eba --- /dev/null +++ b/Utilities/Utils.h @@ -0,0 +1,72 @@ +#include "Includes.h" + +#ifndef __Utils +#define __Utils + +std::string& refTrim(std::string &s); +int setNonblocking(int fd); + + +inline const char* toString(bool b) +{ + return b ? "true" : "false"; +} + +inline const char* runStatus(bool b) +{ + return b? "Running" : "Paused"; +} + + +inline float AddPctF(float& f, const int pct) +{ + return f + f * pct / 100.f; +} + +inline float CalculatePctF(float& f, const int pct) +{ + return f * pct / 100.f; +} + +inline int AddPctN(int& i, const int pct) +{ + return i + i * pct / 100.f; +} + +inline int CalculatePctN(int& i, const int pct) +{ + return i * pct / 100.f; +} + +struct StringComparsionObject +{ + bool operator()(const char* s1, const char* s2) const + { + return strcmp(s1, s2) < 0; + } + bool operator()(std::string s1, std::string s2) const + { + return s1.compare(s2) < 0; + } +}; + +template +bool isWithinList(T valueToCompare, unsigned int count, ...) +{ + va_list v; + va_start(v, count); + + for (unsigned int i = 0; i < count; i++) + { + T arg = va_arg(v, T); + if (valueToCompare == arg) + { + va_end(v); + return true; + } + } + va_end(v); + return false; +} + +#endif // __Utils diff --git a/config.conf b/config.conf new file mode 100644 index 0000000..386a4f0 --- /dev/null +++ b/config.conf @@ -0,0 +1,56 @@ +# Server.LogLevel -- int value +# sets main application log level +# 0 - Minimal +# 1 - Control +# 2 - Debug +Server.LogLevel = 3 + +# Server.Log -- bool value +# enables main applicaiton logging +# 0 - Disabled +# 1 - Enabled +Server.Log = 1 + +# Server.Daemonize -- bool value +# invokes main application to run as daemon +# 0 - Disabled +# 1 - Enabled +Server.Daemonize = 0 + +# Protocol.BindPort -- short value ( 0 - 65535 ) +# sets main listening socket bind port +Protocol.BindPort = 35000 + +# Protocol.BindIp -- string value +# sets main listneing socket bind IP ( 0.0.0.0 all interfaces ) +# a.b.c.d +Protocol.BindIp = 0.0.0.0 + +# Protocol.ProtocolName -- string value +# sets protocol name +Protocol.ProtocolName = HTTP + +# Protocol.RecvFunc -- string value +# sets protocol onRecieve function name +Protocol.RecvFunc = processRecieve + +# Protocol.RecvFunc -- string value +# sets protocol onSend function name +Protocol.SendFunc = processRecieve + +# Protocol.ConnectFunc -- string value +# sets protocol onConnect function name +Protocol.ConnectFunc = processConnect + +# Protocol.DisconnectFunc -- string value +# sets protocol onDisconnect function name +Protocol.DisconnectFunc = processDisconnect + +# Protocol.LoadFunc -- string value +# sets protocol onLoad function name +# called when main application loads library +Protocol.LoadFunc = Init + +# Protocol.LibraryPath -- string value +# sets path to library +Protocol.LibraryPath = ./libFTP.so