Code cleanup (WIP)

This commit is contained in:
Naim A 2016-01-23 20:39:03 +02:00
parent edaa44bfc7
commit 1db33eb0b6
12 changed files with 213 additions and 911 deletions

View file

@ -20,7 +20,6 @@
#ifndef DATABASE_HPP_
#define DATABASE_HPP_
#include "../settings.hpp"
#include <boost/program_options.hpp>
namespace UDPT

33
src/exceptions.h Normal file
View file

@ -0,0 +1,33 @@
#pragma once
namespace UDPT
{
class UDPTException
{
public:
UDPTException(const char* errorMsg = "", int errorCode = 0) : m_error(errorMsg), m_errorCode(errorCode)
{
}
virtual const char* what() const
{
return m_error;
}
virtual int getErrorCode() const
{
return m_errorCode;
}
virtual ~UDPTException()
{
}
protected:
const char* m_error;
const int m_errorCode;
};
}

View file

@ -97,36 +97,12 @@ namespace UDPT
return true;
}
WebApp::WebApp(HTTPServer *srv, DatabaseDriver *db, const boost::program_options::variables_map& conf) : m_conf(conf)
WebApp::WebApp(std::shared_ptr<HTTPServer> srv, DatabaseDriver *db, const boost::program_options::variables_map& conf) : m_conf(conf), m_server(srv)
{
this->instance = srv;
this->db = db;
/* this->sc_api = settings->getClass("api");
// TODO: Implement authentication by keys
Settings::SettingClass *apiKeys = settings->getClass("api.keys");
if (apiKeys != NULL)
{
map<string, string>* aK = apiKeys->getMap();
map<string, string>::iterator it, end;
end = aK->end();
for (it = aK->begin();it != end;it++)
{
string key = it->first;
list<uint32_t> ips;
string::size_type strp = 0;
uint32_t ip;
while ((ip = _getNextIPv4(strp, it->second)) != 0)
{
ips.push_back( m_hton32(ip) );
}
this->ip_whitelist.insert(pair<string, list<uint32_t> >(key, ips));
}
} */
srv->setData("webapp", this);
m_server->setData("webapp", this);
}
WebApp::~WebApp()
@ -136,14 +112,14 @@ namespace UDPT
void WebApp::deploy()
{
list<string> path;
this->instance->addApp(&path, &WebApp::handleRoot);
m_server->addApp(&path, &WebApp::handleRoot);
path.push_back("api");
this->instance->addApp(&path, &WebApp::handleAPI); // "/api"
m_server->addApp(&path, &WebApp::handleAPI); // "/api"
path.pop_back();
path.push_back("announce");
this->instance->addApp(&path, &WebApp::handleAnnounce);
m_server->addApp(&path, &WebApp::handleAnnounce);
}
void WebApp::handleRoot(HTTPServer *srv, HTTPServer::Request *req, HTTPServer::Response *resp)
@ -201,7 +177,7 @@ namespace UDPT
void WebApp::doAddTorrent (HTTPServer::Request *req, HTTPServer::Response *resp)
{
string strHash = req->getParam("hash");
std::string strHash = req->getParam("hash");
if (strHash.length() != 40)
{
resp->write("{\"error\":\"Hash length must be 40 characters.\"}");
@ -232,7 +208,7 @@ namespace UDPT
throw ServerException (0, "IPv4 supported Only.");
}
string key = req->getParam("auth");
std::string key = req->getParam("auth");
if (key.length() <= 0)
throw ServerException (0, "Bad Authentication Key");
@ -247,7 +223,7 @@ namespace UDPT
return;
}
string action = req->getParam("action");
std::string action = req->getParam("action");
if (action == "add")
app->doAddTorrent(req, resp);
else if (action == "remove")

View file

@ -21,10 +21,10 @@
#include "httpserver.hpp"
#include "../db/database.hpp"
#include "../settings.hpp"
#include <stdint.h>
#include <map>
#include <string>
#include <memory>
#include <boost/program_options.hpp>
using namespace std;
@ -38,13 +38,13 @@ namespace UDPT
class WebApp
{
public:
WebApp(HTTPServer *, DatabaseDriver *, const boost::program_options::variables_map& conf);
~WebApp();
WebApp(std::shared_ptr<HTTPServer> , DatabaseDriver *, const boost::program_options::variables_map& conf);
virtual ~WebApp();
void deploy ();
private:
HTTPServer *instance;
std::shared_ptr<HTTPServer> m_server;
UDPT::Data::DatabaseDriver *db;
const boost::program_options::variables_map& m_conf;
std::map<std::string, list<uint32_t> > ip_whitelist;

View file

@ -27,10 +27,10 @@ using namespace std;
namespace UDPT {
Logger::Logger(const boost::program_options::variables_map& s)
: logfile (&std::cout)
: m_logfile (std::cout)
{
const string& filename = s["logging.filename"].as<std::string>();
const string& level = s["logging.level"].as<std::string>();
const std::string& filename = s["logging.filename"].as<std::string>();
const std::string& level = s["logging.level"].as<std::string>();
closeStreamOnDestroy = false;
@ -42,35 +42,10 @@ namespace UDPT {
this->loglevel = LL_INFO;
else
this->loglevel = LL_ERROR;
if (filename.compare("stdout") != 0 && filename.length() > 0)
{
fstream fs;
fs.open(filename.c_str(), ios::binary | ios::out | ios::app);
if (!fs.is_open())
{
this->log(LL_ERROR, "Failed to open log file.");
return;
}
this->logfile = &fs;
closeStreamOnDestroy = true;
}
}
Logger::Logger(const boost::program_options::variables_map& s, ostream &os)
: logfile (&os), loglevel (LL_ERROR)
{
closeStreamOnDestroy = false;
}
Logger::~Logger()
{
fstream *f = (fstream*)this->logfile;
f->flush();
if (closeStreamOnDestroy)
{
f->close();
}
}
void Logger::log(enum LogLevel lvl, string msg)
@ -78,7 +53,7 @@ namespace UDPT {
const char letters[] = "EWID";
if (lvl <= this->loglevel)
{
(*logfile) << time (NULL) << ": ("
m_logfile << time (NULL) << ": ("
<< ((char)letters[lvl]) << "): "
<< msg << "\n";
}

View file

@ -20,7 +20,6 @@
#ifndef LOGGING_H_
#define LOGGING_H_
#include "settings.hpp"
#include <string>
#include <iostream>
#include <queue>
@ -28,7 +27,6 @@
#include <boost/program_options.hpp>
namespace UDPT {
using namespace std;
class Logger
{
@ -42,17 +40,15 @@ namespace UDPT {
Logger(const boost::program_options::variables_map& s);
Logger(const boost::program_options::variables_map& s, ostream &os);
virtual ~Logger();
void log(enum LogLevel, string msg);
void log(enum LogLevel, std::string msg);
private:
ostream *logfile;
std::ostream& m_logfile;
enum LogLevel loglevel;
bool closeStreamOnDestroy;
static void setStream(Logger *logger, ostream &s);
static void setStream(Logger *logger, std::ostream &s);
};
};

View file

@ -19,128 +19,35 @@
#include <iostream>
#include "logging.h"
#include "multiplatform.h"
#include "udpTracker.hpp"
#include "settings.hpp"
#include "http/httpserver.hpp"
#include "http/webapp.hpp"
#include <cstdlib> // atoi
#include <csignal> // signal
#include <cstring> // strlen
#include <memory.h>
#include <memory>
#include <boost/program_options.hpp>
using namespace std;
using namespace UDPT;
using namespace UDPT::Server;
#include "logging.h"
#include "multiplatform.h"
#include "udpTracker.hpp"
#include "http/httpserver.hpp"
#include "http/webapp.hpp"
Logger *logger;
static struct {
Settings *settings;
UDPTracker *usi;
WebApp *wa;
HTTPServer *httpserver;
} Instance;
UDPT::Logger *logger;
static void _print_usage ()
{
cout << "Usage: udpt [<configuration file>]" << endl;
}
static void _doAPIStart (const boost::program_options::variables_map& settings, WebApp **wa, HTTPServer **srv, DatabaseDriver *drvr)
{
if (!settings["apiserver.enable"].as<bool>())
{
return;
}
try
{
*srv = Instance.httpserver = new HTTPServer(settings);
*wa = Instance.wa = new WebApp(*srv, drvr, settings);
(*wa)->deploy();
}
catch (const ServerException &e)
{
std::cerr << "ServerException #" << e.getErrorCode() << ": " << e.getErrorMsg() << endl;
}
}
/**
* Sets current working directory to executables directory.
*/
static void _setCWD (char *argv0)
{
#ifdef WIN32
wchar_t strFileName [MAX_PATH];
DWORD r, i;
r = GetModuleFileNameW(NULL, strFileName, MAX_PATH);
for (i = r;i >= 0;i--)
{
if (strFileName[i] == '\\')
{
strFileName[i] = '\0';
break;
}
}
SetCurrentDirectoryW(strFileName);
#elif defined(linux)
int len, i;
char *strFN;
if (argv0 != NULL)
{
len = strlen (argv0);
strFN = new char [len + 1];
for (i = len;i >= 0;i--)
{
if (strFN[i] == '/')
{
strFN = '\0';
break;
}
}
chdir (strFN);
delete [] strFN;
}
#endif
}
/**
* Releases resources before exit.
*/
static void _doCleanup ()
{
delete Instance.wa;
delete Instance.httpserver;
delete Instance.usi;
delete Instance.settings;
delete logger;
memset (&Instance, 0, sizeof(Instance));
logger = NULL;
}
static void _signal_handler (int sig)
{
stringstream ss;
ss << "Signal " << sig << " raised. Terminating...";
std::stringstream ss;
ss << "Signal " << sig << " raised. ";
logger->log(Logger::LL_INFO, ss.str());
_doCleanup();
}
int main(int argc, char *argv[])
{
UDPTracker *usi;
int r;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
::WSAStartup(MAKEWORD(2, 2), &wsadata);
#endif
boost::program_options::options_description commandLine("Command line options");
@ -194,7 +101,7 @@ int main(int argc, char *argv[])
}
std::string config_filename(var_map["config"].as<std::string>());
bool isTest = var_map.count("test");
bool isTest = (0 != var_map.count("test"));
if (var_map.count("config"))
{
@ -218,8 +125,6 @@ int main(int argc, char *argv[])
}
}
memset(&Instance, 0, sizeof(Instance));
#ifdef SIGBREAK
signal(SIGBREAK, &_signal_handler);
#endif
@ -235,7 +140,7 @@ int main(int argc, char *argv[])
try
{
logger = new Logger(var_map);
logger = new UDPT::Logger(var_map);
}
catch (const std::exception& ex)
{
@ -243,41 +148,42 @@ int main(int argc, char *argv[])
return -1;
}
usi = Instance.usi = new UDPTracker(var_map);
std::shared_ptr<UDPTracker> tracker;
std::shared_ptr<UDPT::Server::HTTPServer> apiSrv;
std::shared_ptr<UDPT::Server::WebApp> webApp;
HTTPServer *apiSrv = NULL;
WebApp *wa = NULL;
try
{
tracker = std::shared_ptr<UDPTracker>(new UDPTracker(var_map));
tracker->start();
r = usi->start();
if (r != UDPTracker::START_OK)
if (var_map["apiserver.enable"].as<bool>())
{
cerr << "Error While trying to start server." << endl;
switch (r)
try
{
case UDPTracker::START_ESOCKET_FAILED:
cerr << "Failed to create socket." << endl;
break;
case UDPTracker::START_EBIND_FAILED:
cerr << "Failed to bind socket." << endl;
break;
default:
cerr << "Unknown Error" << endl;
break;
apiSrv = std::shared_ptr<UDPT::Server::HTTPServer>(new UDPT::Server::HTTPServer(var_map));
webApp = std::shared_ptr<UDPT::Server::WebApp>(new UDPT::Server::WebApp(apiSrv, tracker->conn, var_map));
webApp->deploy();
}
goto cleanup;
catch (const UDPT::Server::ServerException &e)
{
std::cerr << "ServerException #" << e.getErrorCode() << ": " << e.getErrorMsg() << endl;
}
}
}
catch (const UDPT::UDPTException& ex)
{
std::cerr << "UDPTException: " << ex.what() << std::endl;
}
_doAPIStart(var_map, &wa, &apiSrv, usi->conn);
std::cout << "Hit Control-C to exit." << endl;
cout << "Hit Control-C to exit." << endl;
tracker->wait();
usi->wait();
cleanup:
cout << endl << "Goodbye." << endl;
std::cout << endl << "Goodbye." << endl;
#ifdef WIN32
WSACleanup();
::WSACleanup();
#endif
return 0;

View file

@ -28,7 +28,7 @@
#define linux
#endif
#define VERSION "1.0.0-beta"
#define VERSION "1.0.2-dev"
#ifdef WIN32
#include <winsock2.h>

View file

@ -1,449 +0,0 @@
/*
*
* Copyright © 2012-2016 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "settings.hpp"
#include <string.h> // still primitive - need for strlen()
#include <ctype.h> // need for isspace()
#include <exception>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "tools.h"
using namespace std;
namespace UDPT
{
Settings::SettingClass* Settings::getClass(const string classname)
{
if (classname == "")
return NULL;
map<string, SettingClass*>::iterator it;
it = this->classes.find(classname);
if (it == this->classes.end())
return NULL;
else
return it->second;
return NULL;
}
Settings::Settings (const string filename)
{
this->filename = filename;
this->classes.clear();
}
static
void _settings_clean_string (char **str)
{
int len,
i,
offset;
len = strlen(*str);
//strip leading whitespaces.
offset = 0;
for (i = 0;i < len;i++)
{
if (isspace(*str[i]) == 0)
break;
offset++;
}
(*str) += offset;
len -= offset;
for (i = len - 1;i >= 0;i--)
{
if (isspace( (*str)[i] ) != 0)
{
(*str)[i] = '\0';
}
else
break;
}
}
void Settings::parseSettings (char *data, int len)
{
char *className, *key, *value;
int i,
cil; // cil = Chars in line.
char c;
className = key = value = NULL;
cil = 0;
for (i = 0;i < len;i++)
{
c = data[i];
if (c == '\n')
{
cil = 0;
continue;
}
if (cil == 0 && (c == ';' || c == '#'))
{
while (i < len)
{
if (data[i] == '\n')
break;
i++;
}
continue;
}
if (isspace(c) != 0 && cil == 0)
{
continue;
}
if (cil == 0 && c == '[')
{
className = (char*)(i + data + 1);
while (i < len)
{
if (data[i] != ']')
{
i++;
continue;
}
data[i] = '\0';
break;
}
continue;
}
if (isgraph(c) != 0 && cil == 0) // must be a key.
{
key = (char*)(i + data);
while (i < len)
{
if (data[i] == '\n')
{
key = NULL;
break;
}
if (data[i] == '=')
{
data[i] = '\0';
value = (char*)(data + i + 1);
while (i < len)
{
if (data[i] == '\n')
{
data[i] = '\0';
_settings_clean_string(&key);
_settings_clean_string(&value);
// add to settings...
this->set (className, key, value);
cil = 0;
break;
}
i++;
}
break;
}
i++;
}
continue;
}
if (isgraph(c) != 0)
{
cil++;
}
}
}
bool Settings::load()
{
int len;
char *buffer;
fstream cfg;
cfg.open(this->filename.c_str(), ios::in | ios::binary);
if (!cfg.is_open())
return false;
cfg.seekg(0, ios::end);
len = cfg.tellg();
cfg.seekg(0, ios::beg);
buffer = new char [len];
cfg.read(buffer, len);
cfg.close();
this->parseSettings(buffer, len);
delete[] buffer;
return true;
}
bool Settings::save ()
{
SettingClass *sclass;
fstream cfg (this->filename.c_str(), ios::binary | ios::out);
if (!cfg.is_open())
return false;
cfg << "; udpt Settings File - Created Automatically.\n";
map<string, SettingClass*>::iterator it;
for (it = this->classes.begin();it != this->classes.end();it++)
{
sclass = it->second;
cfg << "[" << it->first.c_str() << "]\n";
map<string, string>::iterator rec;
for (rec = sclass->entries.begin();rec != sclass->entries.end();rec++)
{
cfg << rec->first.c_str() << "=" << rec->second.c_str() << "\n";
}
cfg << "\n";
}
cfg.close();
return 0;
}
Settings::~Settings()
{
map<string, SettingClass*>::iterator it;
for (it = this->classes.begin();it != this->classes.end();it++)
{
SettingClass *sc = it->second;
delete sc;
}
this->classes.clear();
}
string Settings::get (const string classN, const string name)
{
SettingClass *c;
c = this->getClass(classN);
if (c == NULL)
return "";
return c->get(name);
}
bool Settings::set (const string classN, const string name, const string value)
{
SettingClass *c;
if (classN == "" || name == "" || value == "")
return false;
c = this->getClass (classN);
if (c == NULL)
{
c = new SettingClass(classN);
this->classes.insert(pair<string, SettingClass*>(classN, c));
}
return c->set (name, value);
}
Settings::SettingClass::SettingClass(const string cn)
{
this->className = cn;
}
string Settings::SettingClass::get (const string& name)
{
if (this->entries.find(name) == this->entries.end())
return "";
return this->entries[name];
}
inline static int _isTrue (string str)
{
int i, // loop index
len; // string's length
if (str == "")
return -1;
len = str.length();
for (i = 0;i < len;i++)
{
if (str[i] >= 'A' && str[i] <= 'Z')
{
str[i] = (str[i] - 'A' + 'a');
}
}
if (str.compare ("yes") == 0)
return 1;
if (str.compare ("no") == 0)
return 0;
if (str.compare("true") == 0)
return 1;
if (str.compare ("false") == 0)
return 0;
if (str.compare("1") == 0)
return 1;
if (str.compare ("0") == 0)
return 0;
return -1;
}
bool Settings::SettingClass::getBool(const string& name)
{
string v = this->get(name);
int r = _isTrue(v);
if (r == 0 || r == 1)
return (bool)r;
throw SettingsException("Invalid boolean value.");
}
bool Settings::SettingClass::getBool (const string& key, bool defaultValue)
{
try {
return this->getBool(key);
} catch (SettingsException &e)
{ }
return defaultValue;
}
void Settings::SettingClass::getIPs (const string& key, list<SOCKADDR_IN> &ip)
{
string v = this->get(key) + " "; // add padding for last entry.
// expect a.b.c.d[:port], IPv4 only supported with BEP-15.
string::size_type s, e;
s = e = 0;
char c;
for (string::size_type i = 0;i < v.length();i++)
{
c = v[i];
if (isspace(c) != 0 || c == ';' || c == ',')
{
if (s == e)
s = e = i;
else
{
string addr = v.substr(s, (e - s) + 1);
SOCKADDR_IN saddr;
memset(&saddr, 0, sizeof (SOCKADDR_IN));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = 0L;
saddr.sin_port = (6969);
{
uint8_t b; // temporary container for IP byte
uint16_t port;
uint32_t ip;
unsigned i, // loop index
stage; // 0,1,2,3=IP[a.b.c.d], 4=port
ip = 0;
b = 0;
stage = 0;
for (i = 0;i < addr.length();i++)
{
if (addr[i] >= '0' && addr[i] <= '9')
{
if (stage <= 3)
{
b *= 10;
b += (addr[i] - '0');
}
else if (stage == 4)
{
port *= 10;
port += (addr[i] - '0');
}
}
else if (addr[i] == '.' && stage < 3)
{
stage ++;
ip *= 256;
ip += b;
b = 0;
}
else if (addr[i] == ':')
{
stage++;
port = 0;
ip *= 256;
ip += b;
}
}
if (stage == 3) // port not provided.
{
port = 6969;
// add last byte.
ip *= 256;
ip += b;
}
saddr.sin_addr.s_addr = m_hton32(ip);
saddr.sin_port = m_hton16(port);
}
ip.push_back(saddr);
s = e = i + 1;
}
}
else
{
e = i;
}
}
}
int Settings::SettingClass::getInt (const string& key, int def)
{
string v = this->get (key);
if (v.length() == 0)
return def;
return std::atoi(v.c_str());
}
map<string, string>* Settings::SettingClass::getMap()
{
return &this->entries;
}
bool Settings::SettingClass::set (const string name, const string value)
{
pair<map<string, string>::iterator, bool> r;
r = this->entries.insert(pair<string, string>(name, value));
if (!r.second)
{
r.first->second = value;
}
return true;
}
};

View file

@ -1,121 +0,0 @@
/*
*
* Copyright © 2012-2016 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <map>
#include <string>
#include <list>
#include "multiplatform.h"
using namespace std;
namespace UDPT
{
class Settings
{
public:
class SettingsException : public std::exception
{
public:
SettingsException (const char *str)
{
this->str = str;
}
const char * what ()
{
return str;
}
private:
const char *str;
};
class SettingClass
{
public:
SettingClass (const string className);
bool set (const string key, const string value);
string get (const string& key);
bool getBool (const string& key);
bool getBool (const string& key, bool defaultValue);
int getInt (const string& key, int def = -1);
map<string, string>* getMap ();
void getIPs (const string& key, list<SOCKADDR_IN> &ip);
private:
friend class Settings;
string className;
map<string, string> entries;
};
/**
* Initializes the settings type.
* @param filename the settings filename.
*/
Settings (const string filename);
/**
* Gets a setting from a Settings type.
* @param class The class of the requested setting.
* @param name The name of the requested setting.
* @return The value for the requested setting, NULL if not available.
*/
SettingClass* getClass (const string name);
/**
* Loads settings from file
* @return true on success, otherwise false.
*/
bool load ();
/**
* Saves settings to file.
* @return true on success; otherwise false.
*/
bool save ();
/**
* Sets a setting in a settings type.
* @param className The class of the setting.
* @param key The name of the setting.
* @param value The value to set for the setting.
* @return true on success, otherwise false.
*/
bool set (const string className, const string key, const string value);
/**
* Gets the requested SettingClass.
* @param classname The name of the class to find (case sensitive).
* @return a pointer to the found class, or NULL if not found.
*/
string get (const string className, const string key);
/**
* Destroys the settings "object"
*/
virtual ~Settings ();
private:
string filename;
map<string, SettingClass*> classes;
void parseSettings (char *data, int len);
};
};

View file

@ -17,19 +17,19 @@
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "udpTracker.hpp"
#include "tools.h"
#include <cstdlib> // atoi
#include <cstring>
#include <ctime>
#include <iostream>
#include <sstream>
#include <list>
#include "udpTracker.hpp"
#include "tools.h"
#include "multiplatform.h"
#include "logging.h"
extern UDPT::Logger *logger;
using namespace std;
using namespace UDPT::Data;
#define UDP_BUFFER_SIZE 2048
@ -39,146 +39,146 @@ namespace UDPT
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf)
{
this->allowRemotes = conf["tracker.allow_remotes"].as<bool>();
this->allowIANA_IPs = conf["tracker.allow_iana_ips"].as<bool>();
this->isDynamic = conf["tracker.is_dynamic"].as<bool>();
this->m_allowRemotes = conf["tracker.allow_remotes"].as<bool>();
this->m_allowIANA_IPs = conf["tracker.allow_iana_ips"].as<bool>();
this->m_isDynamic = conf["tracker.is_dynamic"].as<bool>();
this->announce_interval = conf["tracker.announce_interval"].as<unsigned>();
this->cleanup_interval = conf["tracker.cleanup_interval"].as<unsigned>();
this->port = conf["tracker.port"].as<unsigned short>();
this->thread_count = conf["tracker.threads"].as<unsigned>() + 1;
this->m_announceInterval = conf["tracker.announce_interval"].as<unsigned>();
this->m_cleanupInterval = conf["tracker.cleanup_interval"].as<unsigned>();
this->m_port = conf["tracker.port"].as<unsigned short>();
this->m_threadCount = conf["tracker.threads"].as<unsigned>() + 1;
list<SOCKADDR_IN> addrs;
std::list<SOCKADDR_IN> addrs;
if (addrs.empty())
{
SOCKADDR_IN sa;
sa.sin_port = m_hton16(port);
sa.sin_port = m_hton16(m_port);
sa.sin_addr.s_addr = 0L;
addrs.push_back(sa);
}
this->localEndpoint = addrs.front();
this->m_localEndpoint = addrs.front();
this->threads = new HANDLE[this->thread_count];
this->m_threads = new HANDLE[this->m_threadCount];
this->isRunning = false;
this->conn = NULL;
this->m_isRunning = false;
this->conn = nullptr;
}
UDPTracker::~UDPTracker()
{
int i; // loop index
this->isRunning = false;
this->m_isRunning = false;
// drop listener connection to continue thread loops.
// wait for request to finish (1 second max; allot of time for a computer!).
#ifdef linux
close (this->sock);
::close(this->m_sock);
sleep (1);
::sleep(1);
#elif defined (WIN32)
closesocket (this->sock);
::closesocket(this->m_sock);
Sleep (1000);
::Sleep(1000);
#endif
for (i = 0;i < this->thread_count;i++)
for (i = 0;i < this->m_threadCount;i++)
{
#ifdef WIN32
TerminateThread (this->threads[i], 0x00);
::TerminateThread(this->m_threads[i], 0x00);
#elif defined (linux)
pthread_detach (this->threads[i]);
pthread_cancel (this->threads[i]);
::pthread_detach(this->m_threads[i]);
::pthread_cancel(this->m_threads[i]);
#endif
stringstream str;
str << "Thread (" << (i + 1) << "/" << ((int)this->thread_count) << ") terminated.";
std::stringstream str;
str << "Thread (" << (i + 1) << "/" << ((int)this->m_threadCount) << ") terminated.";
logger->log(Logger::LL_INFO, str.str());
}
if (this->conn != NULL)
delete this->conn;
delete[] this->threads;
delete[] this->m_threads;
}
void UDPTracker::wait()
{
#ifdef WIN32
WaitForMultipleObjects(this->thread_count, this->threads, TRUE, INFINITE);
WaitForMultipleObjects(this->m_threadCount, this->m_threads, TRUE, INFINITE);
#else
int i;
for (i = 0;i < this->thread_count; i++)
for (i = 0;i < this->m_threadCount; i++)
{
pthread_join (this->threads[i], NULL);
pthread_join (this->m_threads[i], NULL);
}
#endif
}
enum UDPTracker::StartStatus UDPTracker::start ()
void UDPTracker::start()
{
stringstream ss;
std::stringstream ss;
SOCKET sock;
int r, // saves results
i, // loop index
yup; // just to set TRUE
string dbname;// saves the Database name.
std::string dbname;// saves the Database name.
sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
return START_ESOCKET_FAILED;
{
throw UDPT::UDPTException("Failed to create socket");
}
yup = 1;
::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yup, 1);
this->localEndpoint.sin_family = AF_INET;
r = ::bind(sock, (SOCKADDR*)&this->localEndpoint, sizeof(SOCKADDR_IN));
this->m_localEndpoint.sin_family = AF_INET;
r = ::bind(sock, reinterpret_cast<SOCKADDR*>(&this->m_localEndpoint), sizeof(SOCKADDR_IN));
if (r == SOCKET_ERROR)
{
#ifdef WIN32
closesocket (sock);
::closesocket(sock);
#elif defined (linux)
close (sock);
::close(sock);
#endif
return START_EBIND_FAILED;
throw UDPT::UDPTException("Failed to bind socket.");
}
this->sock = sock;
this->m_sock = sock;
this->conn = new Data::SQLite3Driver(m_conf, this->isDynamic);
this->conn = new Data::SQLite3Driver(m_conf, this->m_isDynamic);
this->isRunning = true;
this->m_isRunning = true;
ss.str("");
ss << "Starting maintenance thread (1/" << ((int)this->thread_count) << ")";
ss << "Starting maintenance thread (1/" << ((int)this->m_threadCount) << ")";
logger->log(Logger::LL_INFO, ss.str());
// create maintainer thread.
#ifdef WIN32
this->threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_maintainance_start, (LPVOID)this, 0, NULL);
this->m_threads[0] = ::CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(_maintainance_start), (LPVOID)this, 0, NULL);
#elif defined (linux)
pthread_create (&this->threads[0], NULL, _maintainance_start, (void*)this);
::pthread_create (&this->m_threads[0], NULL, _maintainance_start, (void*)this);
#endif
for (i = 1;i < this->thread_count; i++)
for (i = 1;i < this->m_threadCount; i++)
{
ss.str("");
ss << "Starting thread (" << (i + 1) << "/" << ((int)this->thread_count) << ")";
ss << "Starting thread (" << (i + 1) << "/" << ((int)this->m_threadCount) << ")";
logger->log(Logger::LL_INFO, ss.str());
#ifdef WIN32
this->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)this, 0, NULL);
this->m_threads[i] = ::CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(_thread_start), (LPVOID)this, 0, NULL);
#elif defined (linux)
pthread_create (&(this->threads[i]), NULL, _thread_start, (void*)this);
::pthread_create (&(this->m_threads[i]), NULL, _thread_start, (void*)this);
#endif
}
return START_OK;
}
int UDPTracker::sendError (UDPTracker *usi, SOCKADDR_IN *remote, uint32_t transactionID, const string &msg)
int UDPTracker::sendError(UDPTracker* usi, SOCKADDR_IN* remote, uint32_t transactionID, const std::string &msg)
{
struct udp_error_response error;
int msg_sz, // message size to send.
@ -195,24 +195,22 @@ namespace UDPT
if (msg_sz > 1024)
return -1;
memcpy(buff, &error, 8);
::memcpy(buff, &error, 8);
for (i = 8;i <= msg_sz;i++)
{
buff[i] = msg[i - 8];
}
sendto(usi->sock, buff, msg_sz, 0, (SOCKADDR*)remote, sizeof(*remote));
::sendto(usi->m_sock, buff, msg_sz, 0, reinterpret_cast<SOCKADDR*>(remote), sizeof(*remote));
return 0;
}
int UDPTracker::handleConnection(UDPTracker *usi, SOCKADDR_IN *remote, char *data)
{
ConnectionRequest *req;
ConnectionRequest *req = reinterpret_cast<ConnectionRequest*>(data);
ConnectionResponse resp;
req = (ConnectionRequest*)data;
resp.action = m_hton32(0);
resp.transaction_id = req->transaction_id;
@ -223,7 +221,7 @@ namespace UDPT
return 1;
}
sendto(usi->sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
::sendto(usi->m_sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
return 0;
}
@ -258,7 +256,7 @@ namespace UDPT
req->num_want = m_hton32 (req->num_want);
req->left = m_hton64 (req->left);
if (!usi->allowRemotes && req->ip_address != 0)
if (!usi->m_allowRemotes && req->ip_address != 0)
{
UDPTracker::sendError (usi, remote, req->transaction_id, "Tracker doesn't allow remote IP's; Request ignored.");
return 0;
@ -309,7 +307,7 @@ namespace UDPT
resp = (AnnounceResponse*)buff;
resp->action = m_hton32(1);
resp->interval = m_hton32 ( usi->announce_interval );
resp->interval = m_hton32 ( usi->m_announceInterval );
resp->leechers = m_hton32(tE.leechers);
resp->seeders = m_hton32 (tE.seeders);
resp->transaction_id = req->transaction_id;
@ -331,7 +329,7 @@ namespace UDPT
}
delete[] peers;
sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
::sendto(usi->m_sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
// update DB.
uint32_t ip;
@ -347,7 +345,7 @@ namespace UDPT
int UDPTracker::handleScrape(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len)
{
ScrapeRequest *sR;
ScrapeRequest *sR = reinterpret_cast<ScrapeRequest*>(data);
int v, // validation helper
c, // torrent counter
i, // loop counter
@ -356,9 +354,6 @@ namespace UDPT
ScrapeResponse *resp;
uint8_t buffer [1024]; // up to 74 torrents can be scraped at once (17*74+8) < 1024
sR = (ScrapeRequest*)data;
// validate request length:
v = len - 16;
if (v < 0 || v % 20 != 0)
@ -377,7 +372,7 @@ namespace UDPT
// get torrent count.
c = v / 20;
resp = (ScrapeResponse*)buffer;
resp = reinterpret_cast<ScrapeResponse*>(buffer);
resp->action = m_hton32(2);
resp->transaction_id = sR->transaction_id;
@ -407,7 +402,7 @@ namespace UDPT
*leechers = m_hton32(tE.leechers);
}
sendto (usi->sock, (const char*)buffer, sizeof(buffer), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
::sendto(usi->m_sock, reinterpret_cast<const char*>(buffer), sizeof(buffer), 0, reinterpret_cast<SOCKADDR*>(remote), sizeof(SOCKADDR_IN));
return 0;
}
@ -422,14 +417,12 @@ static int _isIANA_IP (uint32_t ip)
int UDPTracker::resolveRequest (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r)
{
ConnectionRequest *cR;
ConnectionRequest* cR = reinterpret_cast<ConnectionRequest*>(data);
uint32_t action;
cR = (ConnectionRequest*)data;
action = m_hton32(cR->action);
if (!usi->allowIANA_IPs)
if (!usi->m_allowIANA_IPs)
{
if (_isIANA_IP (remote->sin_addr.s_addr))
{
@ -470,23 +463,22 @@ static int _isIANA_IP (uint32_t ip)
int r;
char tmpBuff[UDP_BUFFER_SIZE];
usi = (UDPTracker*)arg;
usi = reinterpret_cast<UDPTracker*>(arg);
addrSz = sizeof(SOCKADDR_IN);
while (usi->isRunning)
while (usi->m_isRunning)
{
cout.flush();
// peek into the first 12 bytes of data; determine if connection request or announce request.
r = recvfrom(usi->sock, (char*)tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
r = ::recvfrom(usi->m_sock, (char*)tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
if (r <= 0)
continue; // bad request...
r = UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r);
}
#ifdef linux
pthread_exit (NULL);
::pthread_exit (NULL);
#endif
return 0;
}
@ -497,18 +489,16 @@ static int _isIANA_IP (uint32_t ip)
void* UDPTracker::_maintainance_start(void *arg)
#endif
{
UDPTracker *usi;
UDPTracker* usi = reinterpret_cast<UDPTracker*>(arg);
usi = (UDPTracker *)arg;
while (usi->isRunning)
while (usi->m_isRunning)
{
usi->conn->cleanup();
#ifdef WIN32
Sleep (usi->cleanup_interval * 1000);
::Sleep(usi->m_cleanupInterval * 1000);
#elif defined (linux)
sleep (usi->cleanup_interval);
::sleep(usi->m_cleanupInterval);
#else
#error Unsupported OS.
#endif

View file

@ -22,18 +22,16 @@
#include <stdint.h>
#include <boost/program_options.hpp>
#include <string>
#include "exceptions.h"
#include "multiplatform.h"
#include "db/driver_sqlite.hpp"
#include "settings.hpp"
#include <boost/program_options.hpp>
#include <string>
using namespace std;
#define UDPT_DYNAMIC 0x01 // Track Any info_hash?
#define UDPT_ALLOW_REMOTE_IP 0x02 // Allow client's to send other IPs?
#define UDPT_ALLOW_IANA_IP 0x04 // allow IP's like 127.0.0.1 or other IANA reserved IPs?
#define UDPT_VALIDATE_CLIENT 0x08 // validate client before adding to Database? (check if connection is open?)
#define UDPT_DYNAMIC (0x01) // Track Any info_hash?
#define UDPT_ALLOW_REMOTE_IP (0x02) // Allow client's to send other IPs?
#define UDPT_ALLOW_IANA_IP (0x04) // allow IP's like 127.0.0.1 or other IANA reserved IPs?
#define UDPT_VALIDATE_CLIENT (0x08) // validate client before adding to Database? (check if connection is open?)
namespace UDPT
@ -122,9 +120,8 @@ namespace UDPT
/**
* Starts the Initialized instance.
* @return 0 on success, otherwise non-zero.
*/
enum StartStatus start ();
void start();
/**
* Joins all threads, and waits for all of them to terminate.
@ -139,17 +136,17 @@ namespace UDPT
Data::DatabaseDriver *conn;
private:
SOCKET sock;
SOCKADDR_IN localEndpoint;
uint16_t port;
uint8_t thread_count;
bool isRunning;
bool isDynamic;
bool allowRemotes;
bool allowIANA_IPs;
HANDLE *threads;
uint32_t announce_interval;
uint32_t cleanup_interval;
SOCKET m_sock;
SOCKADDR_IN m_localEndpoint;
uint16_t m_port;
uint8_t m_threadCount;
bool m_isRunning;
bool m_isDynamic;
bool m_allowRemotes;
bool m_allowIANA_IPs;
HANDLE *m_threads;
uint32_t m_announceInterval;
uint32_t m_cleanupInterval;
const boost::program_options::variables_map& m_conf;
@ -167,7 +164,7 @@ namespace UDPT
static int handleAnnounce(UDPTracker *usi, SOCKADDR_IN *remote, char *data);
static int handleScrape(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len);
static int sendError (UDPTracker *, SOCKADDR_IN *remote, uint32_t transId, const string &);
static int sendError(UDPTracker *, SOCKADDR_IN *remote, uint32_t transId, const std::string &);
};
};