commit
965f9d87c3
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
*.o
|
||||
*.sublime-*
|
||||
|
|
11
Makefile
11
Makefile
|
@ -18,23 +18,22 @@
|
|||
#
|
||||
|
||||
objects = main.o udpTracker.o database.o driver_sqlite.o \
|
||||
settings.o tools.o httpserver.o webapp.o \
|
||||
logging.o
|
||||
tools.o httpserver.o webapp.o logging.o tracker.o
|
||||
target = udpt
|
||||
|
||||
%.o: src/%.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
%.o: src/%.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
$(CXX) -g -std=gnu++11 -c -o $@ $< $(CXXFLAGS)
|
||||
%.o: src/db/%.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
$(CXX) -g -std=gnu++11 -c -o $@ $< $(CXXFLAGS)
|
||||
%.o: src/http/%.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
$(CXX) -g -std=gnu++11 -c -o $@ $< $(CXXFLAGS)
|
||||
all: $(target)
|
||||
|
||||
$(target): $(objects)
|
||||
@echo Linking...
|
||||
$(CXX) -O3 -o $(target) $(objects) $(LDFLAGS) -lsqlite3 -lpthread
|
||||
$(CXX) -O3 -o $(target) $(objects) $(LDFLAGS) -lboost_program_options -lsqlite3 -lpthread -lboost_thread -lboost_system
|
||||
@echo Done.
|
||||
clean:
|
||||
@echo Cleaning Up...
|
||||
|
|
20
README
20
README
|
@ -1,20 +0,0 @@
|
|||
|
||||
What is UDPT?
|
||||
The UDPT project is a BitTorrent Tracking software.
|
||||
It uses the UDP protocol (instead of the HTTP protocol) to track
|
||||
peers downloading the same software. UDPT was written according
|
||||
to BEP 15 of the BitTorrent standard.
|
||||
|
||||
Who Wrote UDPT, and when?
|
||||
UDPT's development started on Nevember 20th, 2012.
|
||||
It was written by Naim A. <naim94a@gmail.com>. Naim wrote this
|
||||
program for fun in his free time.
|
||||
|
||||
Required Software:
|
||||
UDPT depends on SQLite3 (public-domain, compatible with GPL).
|
||||
UDPT's source is designed to be platform portable. It is
|
||||
supported with Windows and with Linux based systems, It should
|
||||
work with Apple's systems but it might not (no officially supported).
|
||||
|
||||
Project page: http://www.github.com/naim94a/udpt
|
||||
|
39
README.md
Normal file
39
README.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
# UDPT
|
||||
The UDPT project is a BitTorrent Tracking software.
|
||||
It uses the UDP protocol (instead of the HTTP protocol) to track
|
||||
peers downloading the same software. UDPT was written according
|
||||
to [BEP 15](http://www.bittorrent.org/beps/bep_0015.html) of the BitTorrent standard.
|
||||
|
||||
UDPT is designed to run on both Windows and Linux-based platform (It may run on Apple systems too).
|
||||
|
||||
### License
|
||||
UDPT is released under the [GPL](http://www.gnu.org/licenses/gpl-3.0.en.html) license, a copy is included in this repository.
|
||||
We use [SQLite3](http://www.sqlite.org/) which is public-domain, and [Boost](http://www.boost.org/) which is released under the [boost license](http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
### Building
|
||||
We didn't really work on creating any installer, at the moment you can just run udpt from anywhere on your filesystem.
|
||||
Building udpt is pretty straightforward, just download the project or clone the repo:
|
||||
|
||||
UDPT requires the SQLite3, boost_program_options and boost_thread develpment packages to be installed.
|
||||
|
||||
<pre>
|
||||
$ git clone https://github.com/naim94a/udpt.git
|
||||
$ cd udpt
|
||||
$ make
|
||||
</pre>
|
||||
|
||||
And finally:
|
||||
|
||||
<pre>
|
||||
$ ./udpt
|
||||
</pre>
|
||||
|
||||
### Links
|
||||
* Documentation can be found at our wiki: https://github.com/naim94a/udpt/wiki
|
||||
* If you have any suggestions or find any bugs, please report them here: https://github.com/naim94a/udpt/issues
|
||||
* Project Page: http://www.github.com/naim94a/udpt
|
||||
|
||||
### Author(s)
|
||||
UDPT was developed by [Naim A.](http://www.github.com/naim94a) at for fun at his free time.
|
||||
The development started on November 20th, 2012.
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -23,9 +23,8 @@ namespace UDPT
|
|||
{
|
||||
namespace Data
|
||||
{
|
||||
DatabaseDriver::DatabaseDriver(Settings::SettingClass *sc, bool isDynamic)
|
||||
DatabaseDriver::DatabaseDriver(const boost::program_options::variables_map& conf, bool isDynamic) : m_conf(conf)
|
||||
{
|
||||
this->dClass = sc;
|
||||
this->is_dynamic = isDynamic;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -20,7 +20,7 @@
|
|||
#ifndef DATABASE_HPP_
|
||||
#define DATABASE_HPP_
|
||||
|
||||
#include "../settings.hpp"
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
|
@ -68,7 +68,7 @@ namespace UDPT
|
|||
* Opens the DB's connection
|
||||
* @param dClass Settings class ('database' class).
|
||||
*/
|
||||
DatabaseDriver (Settings::SettingClass *dClass, bool isDynamic = false);
|
||||
DatabaseDriver(const boost::program_options::variables_map& conf, bool isDynamic = false);
|
||||
|
||||
/**
|
||||
* Adds a torrent to the Database. automatically done if in dynamic mode.
|
||||
|
@ -162,7 +162,7 @@ namespace UDPT
|
|||
virtual ~DatabaseDriver();
|
||||
|
||||
protected:
|
||||
Settings::SettingClass *dClass;
|
||||
const boost::program_options::variables_map& m_conf;
|
||||
private:
|
||||
bool is_dynamic;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -69,13 +69,13 @@ namespace UDPT
|
|||
return data;
|
||||
}
|
||||
|
||||
SQLite3Driver::SQLite3Driver (Settings::SettingClass *sc, bool isDyn) : DatabaseDriver(sc, isDyn)
|
||||
SQLite3Driver::SQLite3Driver(const boost::program_options::variables_map& conf, bool isDyn) : DatabaseDriver(conf, isDyn)
|
||||
{
|
||||
int r;
|
||||
bool doSetup;
|
||||
|
||||
fstream fCheck;
|
||||
string filename = sc->get("file");
|
||||
string filename = m_conf["db.param"].as<std::string>();
|
||||
|
||||
fCheck.open(filename.c_str(), ios::binary | ios::in);
|
||||
if (fCheck.is_open())
|
||||
|
@ -99,7 +99,6 @@ namespace UDPT
|
|||
|
||||
void SQLite3Driver::doSetup()
|
||||
{
|
||||
// cout << "Creating DB..." << endl;
|
||||
char *eMsg = NULL;
|
||||
// for quicker stats.
|
||||
sqlite3_exec(this->db, "CREATE TABLE stats ("
|
||||
|
@ -109,13 +108,11 @@ namespace UDPT
|
|||
"seeders INTEGER DEFAULT 0,"
|
||||
"last_mod INTEGER DEFAULT 0"
|
||||
")", NULL, NULL, &eMsg);
|
||||
// cout << "stats: " << (eMsg == NULL ? "OK" : eMsg) << endl;
|
||||
// for non-Dynamic trackers
|
||||
|
||||
sqlite3_exec(this->db, "CREATE TABLE torrents ("
|
||||
"info_hash blob(20) UNIQUE,"
|
||||
"created INTEGER"
|
||||
")", NULL, NULL, &eMsg);
|
||||
// cout << "torrents: " << (eMsg == NULL ? "OK" : eMsg) << endl;
|
||||
}
|
||||
|
||||
bool SQLite3Driver::getTorrentInfo(TorrentEntry *e)
|
||||
|
@ -209,8 +206,6 @@ namespace UDPT
|
|||
sql += hash;
|
||||
sql += "' (peer_id,ip,port,uploaded,downloaded,left,last_seen) VALUES (?,?,?,?,?,?,?)";
|
||||
|
||||
// printf("IP->%x::%u\n", pE->ip, pE->port);
|
||||
|
||||
sqlite3_prepare(this->db, sql.c_str(), sql.length(), &stmt, NULL);
|
||||
|
||||
sqlite3_bind_blob(stmt, 1, (void*)peer_id, 20, NULL);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -31,7 +31,7 @@ namespace UDPT
|
|||
class SQLite3Driver : public DatabaseDriver
|
||||
{
|
||||
public:
|
||||
SQLite3Driver (Settings::SettingClass *sc, bool isDyn = false);
|
||||
SQLite3Driver(const boost::program_options::variables_map& conf, bool isDyn = false);
|
||||
bool addTorrent(uint8_t info_hash[20]);
|
||||
bool removeTorrent(uint8_t info_hash[20]);
|
||||
bool genConnectionId(uint64_t *connId, uint32_t ip, uint16_t port);
|
||||
|
@ -43,7 +43,7 @@ namespace UDPT
|
|||
bool getPeers(uint8_t info_hash [20], int *max_count, PeerEntry *pe);
|
||||
void cleanup();
|
||||
|
||||
~SQLite3Driver ();
|
||||
virtual ~SQLite3Driver();
|
||||
private:
|
||||
sqlite3 *db;
|
||||
|
||||
|
|
33
src/exceptions.h
Normal file
33
src/exceptions.h
Normal 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;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013 Naim A.
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include <cstring>
|
||||
#include <map>
|
||||
#include "httpserver.hpp"
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -43,22 +44,14 @@ namespace UDPT
|
|||
this->init(sa, threads);
|
||||
}
|
||||
|
||||
HTTPServer::HTTPServer(Settings *s)
|
||||
HTTPServer::HTTPServer(const boost::program_options::variables_map& conf)
|
||||
{
|
||||
Settings::SettingClass *sc = s->getClass("apiserver");
|
||||
list<SOCKADDR_IN> localEndpoints;
|
||||
uint16_t port;
|
||||
int threads;
|
||||
|
||||
port = 6969;
|
||||
threads = 1;
|
||||
|
||||
if (sc != NULL)
|
||||
{
|
||||
port = sc->getInt("port", 6969);
|
||||
threads = sc->getInt("threads", 1);
|
||||
sc->getIPs("bind", localEndpoints);
|
||||
}
|
||||
port = conf["apiserver.port"].as<unsigned short>();
|
||||
threads = conf["apiserver.threads"].as<unsigned short>();
|
||||
|
||||
if (threads <= 0)
|
||||
threads = 1;
|
||||
|
@ -85,13 +78,13 @@ namespace UDPT
|
|||
|
||||
this->rootNode.callback = NULL;
|
||||
|
||||
this->srv = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
this->srv = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (this->srv == INVALID_SOCKET)
|
||||
{
|
||||
throw ServerException (1, "Failed to create Socket");
|
||||
}
|
||||
|
||||
r = bind (this->srv, (SOCKADDR*)&localEndpoint, sizeof(localEndpoint));
|
||||
r = ::bind(this->srv, (SOCKADDR*)&localEndpoint, sizeof(localEndpoint));
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
throw ServerException(2, "Failed to bind socket");
|
||||
|
@ -118,7 +111,7 @@ namespace UDPT
|
|||
doSrv:
|
||||
try {
|
||||
HTTPServer::handleConnections (s);
|
||||
} catch (ServerException &se)
|
||||
} catch (const ServerException &se)
|
||||
{
|
||||
cerr << "SRV ERR #" << se.getErrorCode() << ": " << se.getErrorMsg () << endl;
|
||||
goto doSrv;
|
||||
|
@ -139,13 +132,13 @@ doSrv:
|
|||
|
||||
while (server->isRunning)
|
||||
{
|
||||
r = listen (server->srv, 50);
|
||||
r = ::listen(server->srv, 50);
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep (500);
|
||||
::Sleep(500);
|
||||
#else
|
||||
sleep (1);
|
||||
::sleep(1);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
@ -167,7 +160,7 @@ doSrv:
|
|||
stringstream stream;
|
||||
stream << "<html>";
|
||||
stream << "<head><title>Not Found</title></head>";
|
||||
stream << "<body><h1>Not Found</h1><div>The server couldn't find the request resource.</div><br /><hr /><div style=\"font-size:small;text-align:center;\">© 2013 Naim A. | <a href=\"http://udpt.googlecode.com/\">The UDPT Project</a></div></body>";
|
||||
stream << "<body><h1>Not Found</h1><div>The server couldn't find the request resource.</div><br /><hr /><div style=\"font-size:small;text-align:center;\"><a href=\"http://github.com/naim94a/udpt\">UDPT</a></div></body>";
|
||||
stream << "</html>";
|
||||
string str = stream.str();
|
||||
resp.write (str.c_str(), str.length());
|
||||
|
@ -183,7 +176,7 @@ doSrv:
|
|||
stringstream stream;
|
||||
stream << "<html>";
|
||||
stream << "<head><title>Internal Server Error</title></head>";
|
||||
stream << "<body><h1>Internal Server Error</h1><div>An Error Occurred while trying to process your request.</div><br /><hr /><div style=\"font-size:small;text-align:center;\">© 2013 Naim A. | <a href=\"http://udpt.googlecode.com/\">The UDPT Project</a></div></body>";
|
||||
stream << "<body><h1>Internal Server Error</h1><div>An Error Occurred while trying to process your request.</div><br /><hr /><div style=\"font-size:small;text-align:center;\"><a href=\"http://github.com/naim94a/udpt\">UDPT</a></div></body>";
|
||||
stream << "</html>";
|
||||
string str = stream.str();
|
||||
resp.write (str.c_str(), str.length());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013 Naim A.
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -24,8 +24,8 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <boost/program_options.hpp>
|
||||
#include "../multiplatform.h"
|
||||
#include "../settings.hpp"
|
||||
using namespace std;
|
||||
|
||||
#define REQUEST_BUFFER_SIZE 2048
|
||||
|
@ -131,7 +131,7 @@ namespace UDPT
|
|||
typedef void (reqCallback)(HTTPServer*,Request*,Response*);
|
||||
|
||||
HTTPServer (uint16_t port, int threads);
|
||||
HTTPServer (Settings *s);
|
||||
HTTPServer(const boost::program_options::variables_map& conf);
|
||||
|
||||
void addApp (list<string> *path, reqCallback *);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013 Naim A.
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -97,36 +97,12 @@ namespace UDPT
|
|||
return true;
|
||||
}
|
||||
|
||||
WebApp::WebApp(HTTPServer *srv, DatabaseDriver *db, Settings *settings)
|
||||
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,29 +112,24 @@ 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)
|
||||
{
|
||||
// It would be very appreciated to keep this in the code.
|
||||
resp->write("<html>"
|
||||
"<head><title>Powered by UDPT</title></head>"
|
||||
"<head><title>UDPT Torrent Tracker</title></head>"
|
||||
"<body>"
|
||||
"<h2>The UDPT Project</h2>"
|
||||
"<div style=\"vertical-align:top;\">This tracker is running on UDPT Software.<br />"
|
||||
"UDPT is a open-source project, freely available for anyone to use. If you would like to obtain a copy of the software, you can get it here: <a href=\"http://code.google.com/p/udpt\">http://code.googe.com/p/udpt</a>."
|
||||
"<br /><br />If you would like to help the project grow, please donate for our hard work, effort & time: <a class=\"dbtn\" href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6735UFXPUM7BG\">"
|
||||
"<img src=\"data:image/gif;base64,R0lGODlhkwAvAOZ6AC89cv+yPP+sLP++Wv+pJv7hqP/KeP/syf/Wlv/z3P/25f/itP7pwC9ss//57v7nussDBP/9+OyLNf7mtf+vNARnzeU3M/7ksDZSdBU6Z/7fopWXkgBXoP7enr7BwXqHidHS0+Lj5MnGwdja3Ct8xWg0XQFbx0plfP63RaAQJ1S450hTVbc3QcPHyMjMzcfKzMrd77W7woCs1LSsmOLt9sS7oEA3J5W62qaut4lvS2djULTQ52GTx15yh6t9RkqDuyOZ1WrE77iLPr1nKP7Sh9iaN+dbNZHL7MLU4isgDPLz9s+HRdbJqKWdjfD2+k5FNYybsffU0e+lM2Ci2O/cs+b0+3dwY/KpdtTm9PHx7+7YqG6iyvbCmP308vCmoN/P0IR+c/fhzvjIucrO091hYNezs0iN1+yYQhRZrvPm5t7Knc6Zmu7TmvKcavT6/frq2v/gsLhSSvC2t/XGqOaGhv/v0wAAAAAzZv+ZM////////wAAAAAAAAAAAAAAAAAAACH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDQzREZFNDg5QTg4MTFFMTlFOTA4QkM0NUJFNDFFQzUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDQzREZFNDk5QTg4MTFFMTlFOTA4QkM0NUJFNDFFQzUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNDNERkU0NjlBODgxMUUxOUU5MDhCQzQ1QkU0MUVDNSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNDNERkU0NzlBODgxMUUxOUU5MDhCQzQ1QkU0MUVDNSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAHoALAAAAACTAC8AAAf/gHqCg4SFhoeHeIqLjI2Oj5CRkpOSiJaXmJmahooGCwkRoaKjpKWmp6ipqqQHCIqbsLGyhHhECQ64ubq7vL2+v8DBwXB4s8bHiQsKy8zNzs/Q0dLT1NXLCcXI2rN4Bwnf4OHi4+Tl5ufo6eF12dvumHgddfP09fb3+Pn6+/z9+O3vAhZCcaCgwYMIEypcyLChw4cLtQicOKgWg4sYM2rMuOGOxzsZPlDZSLKkSQZMZpxcuREgRXcBDDyYSbOmzZof7mA4cSLDnRM3gwoduiFDjaFIhQZ4GRAPigETokqdSnXqiTs1olLxyUQqlRpZq05gUoPK1K9hpfo0G5VsV7Fw/6ciQOGSqTGnKIhc2Mu3r1++HrXwzblhb06PGQpfqKGzB2Imhj9mgMzk450NWhx7PCH4r+e+A+ja3YYXBYICqFOrXl2AMQbVOT8UcIxhRhOfagp0/DkDwx3ZM3TOyHmiwIyrGD5oudqj92XW0FUbQCF6NLLSeaND79gD9m81ILWgJjz7J2rHTVY3MV8gdmudqIMX1766Q2jqda3DwhOgf/8BRGgg4IAEDujYBh0M6FsN3A0Ymwa+zSDgghrU0NNHH0x4h4QdZbCTbxgUKKKAHUznXwD56acJfyf29xQRRHQg44wzRjhjRxh0ENuMVzXBhkcy/nhHB2z49EENNnbgm/8aOur0wZMfNEHjlAgQYcAALfaXoorwUODll2CGGaZHXkqRg0dCUODDHSt4WQRIUgjBppdytlknBVL4VAQFb2bg5Zo60LmnmIQSuiWXluAhwKKMNupoo3Ja5pEPi+Z5hw46+ETpmTosyqkAb17q2x2LyplBDkVI4RumOknx6KuvHoooIorCaqsQK+SaK6qNFrGCRxgI4ekKQhAgQA7EGntmsLky+usdRYD6rA7R2mqtrLMmQsC23Hbr7bfghivuuOSWOy622XKS5brstuvuu/DG6y666Rbi1AD45qvvvvz26++/AAcscL/01kuLAQgnrPDCDDfs8MMQRywxwwUbTAv/EQhkrPHGHHfs8ccghyzyyBpXbPHFC6Ss8sost+zyyzDHLPPMHZh8Mi21HODPzjz3zDMxBNxMGiVEF2300Y0IrfTSTDft9NNQRy311FRXbfXVWAst6daSpWBDCj5ZNggAZJdt9tlokz1IHmy37fbbcLM9iAoqBBEE3UDkTcLeDfQ9iB2ABy744IQDLogHhSdeuCCWmWBCBZBXwMEdKaQAweWXe/3R2GaXwMLnJZC9Qg4++IDs2WvHrXrcc9t9twp5A7E3CX038LcIq+eehx2H2xHC78AHL7zwvOvx0eORQ24CAJg3D0EKAHjEOQAlWGD99SzkIMH23Ptgduq65966/910wy47334LYgfu4cddPOIjxC///PTTX7xHySePBvXONy+9IGSr3vUGaATuGXAJZQNf+1gniLqRD2/no1369LA+EYggCyAQQQiyoME3hOF3HBRBBkGQhffZAQQoTKEKV7jC+znOcRVAXgWohwHL9e95d+DcAAlYQANyLwdqE0QeFHClAeSBBj/gwRZ+4IQtoIEDPMjDDn7wg7YNIghHyOIRXjeFLvKAB1S8XRJ08IQkJKEJSQCDD9pwBR9YwQo20MEGnmADEJjwBXjMox73uEcXVsAMZiDBFEgQwxIYsnpk6B/YxlYCMhiBDDs0giTPcIUzcO8MCAQA+JogBQbcgP8DMmgABz7ZgC3IIA+i5IAT5CaIKlTBDVWAAQ1cKUsswMAJMICBGEGQhCdYoZd54MIcouAFG9hgAzb4pRV217sYYCADIYlBDzIAhRhkoAfOhEIGcACADyBOEByIIQyQsAMlyAAJW9gBEmTggTXQYA1y8MIX6HA5G4yNBV8YQR6IKYYoREEMXohCF0bwhjmEgQph4EIQ9dC2G5wAAaKkAQd+QModSJEDGLVoHgZBAxq4wQ0WjaUsc0mDXIoxmUmwwRNWmgM2RmEDYECmFcjITD0gDgc7AQA2yXYCa14TA9rEAAbGgAMXkgAJWQgBDG6ABCVgIQZMXYMXylCGKJABBJf/y8A9lcA2ruYhDfr8ahiWEII8hEABabjCCjQpRLbBgAMfmOgOoOiEH2SUB6MEJSv1UD4tZvEGgAWsDGRwu7eBYAaIrYEFGQQ3E+I0p9qcJg6omQEAaBMAGMBBURn3xxggIQZjyCUOkHCDLSABCWX4AgtSK4d6MjKsSuhCCJQwgt/NQAkKYNsXlKAEhbKVoW17Igd28EkZwCAPMuDAFjCK0SpuVBB5UwHbqoAFJ2CBBnlYZUcL6zZMbWAGNgADGHRgA7cp4AomdGZPdArU5GQgBh+gLDd7WjwOOK4BFWiACRpAAhMckgUp+NzzWJC5HALQc59L8OfiEAcjLGEJpYOw/w8yqUC7NgC5w2UuB0T5g1Be+Ll6IAEQpkCD6u6gxCWlAS51qT72LbALXNheenEQA9DiAAQxoPGNczyCG9N4DPcLZ/4gJ9Qa3hCHOtzh9STpw+3ZYKFu24EMLCplGgx2yjeQAXazvNe9/cCLYPyimL/I3fApIMbcM6EH1szmNrvZzfe7w5CVVwIbKvJ/egigkq3XQx96D8oLVN0gZje72hl6guvTXRfE0IYmm7AFkI60pCc96TjLec4msHPzUrA5AAaQBTtkwQqW4EMgJrCtgYbbIA7NakOX+W2LvkKT09w7F9j61rjOda4t7RHkOc4jANB05cTm6bIdMnRlG10OdEuANgWm2opA0EOrp/23Jljw2jWYgQ+GwO1ue5vbJtyAuMdN7nKXm9dcs8yTbbC16aXt3ahD9bOteARpT5vVf1OcvgMniBLuW996CAQAOw==\" alt=\"Donate via PayPal\" />"
|
||||
"</a></div>"
|
||||
"<br /><hr /><div style=\"text-align:center;font-size:small;\">© 2013 Naim A. | Powered by <a href=\"http://code.google.com/p/udpt\">UDPT</a></div>"
|
||||
"<div style=\"vertical-align:top;\">This tracker is running on UDPT Software.</div>"
|
||||
"<br /><hr /><div style=\"text-align:center;font-size:small;\"><a href=\"http://github.com/naim94a/udpt\">UDPT</a></div>"
|
||||
"</body>"
|
||||
"</html>");
|
||||
}
|
||||
|
@ -206,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.\"}");
|
||||
|
@ -237,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");
|
||||
|
||||
|
@ -252,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")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013 Naim A.
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -21,10 +21,11 @@
|
|||
|
||||
#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;
|
||||
|
||||
using namespace UDPT;
|
||||
|
@ -37,15 +38,15 @@ namespace UDPT
|
|||
class WebApp
|
||||
{
|
||||
public:
|
||||
WebApp (HTTPServer *, DatabaseDriver *, Settings *);
|
||||
~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;
|
||||
Settings::SettingClass *sc_api;
|
||||
const boost::program_options::variables_map& m_conf;
|
||||
std::map<std::string, list<uint32_t> > ip_whitelist;
|
||||
|
||||
static void handleRoot (HTTPServer*,HTTPServer::Request*, HTTPServer::Response*);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -26,30 +26,14 @@ using namespace std;
|
|||
|
||||
namespace UDPT {
|
||||
|
||||
Logger::Logger(Settings *s)
|
||||
: logfile (&std::cout)
|
||||
Logger::Logger(const boost::program_options::variables_map& s)
|
||||
: m_logfile (std::cout)
|
||||
{
|
||||
Settings::SettingClass *sc;
|
||||
string filename = "stdout";
|
||||
string level = "error";
|
||||
const std::string& filename = s["logging.filename"].as<std::string>();
|
||||
const std::string& level = s["logging.level"].as<std::string>();
|
||||
|
||||
closeStreamOnDestroy = false;
|
||||
|
||||
sc = s->getClass("logging");
|
||||
if (sc != NULL)
|
||||
{
|
||||
string::size_type i;
|
||||
|
||||
filename = sc->get("filename");
|
||||
level = sc->get("level");
|
||||
|
||||
for (i = 0;i < level.length(); i++)
|
||||
{
|
||||
if (level[i] >= 'A' && level[i] <= 'Z')
|
||||
level[i] = 'a' + (level[i] - 'A');
|
||||
}
|
||||
}
|
||||
|
||||
if (level == "debug" || level == "d")
|
||||
this->loglevel = LL_DEBUG;
|
||||
else if (level == "warning" || level == "w")
|
||||
|
@ -58,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(Settings *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)
|
||||
|
@ -94,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";
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -20,15 +20,15 @@
|
|||
#ifndef LOGGING_H_
|
||||
#define LOGGING_H_
|
||||
|
||||
#include "settings.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <time.h>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace UDPT {
|
||||
using namespace std;
|
||||
class Logger {
|
||||
class Logger
|
||||
{
|
||||
|
||||
public:
|
||||
enum LogLevel {
|
||||
|
@ -38,19 +38,17 @@ namespace UDPT {
|
|||
LL_DEBUG = 3
|
||||
};
|
||||
|
||||
Logger (Settings *s);
|
||||
|
||||
Logger (Settings *s, ostream &os);
|
||||
Logger(const boost::program_options::variables_map& s);
|
||||
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
345
src/main.cpp
345
src/main.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -19,230 +19,173 @@
|
|||
|
||||
#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>
|
||||
#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"
|
||||
#include "tracker.hpp"
|
||||
|
||||
Logger *logger;
|
||||
static struct {
|
||||
Settings *settings;
|
||||
UDPTracker *usi;
|
||||
WebApp *wa;
|
||||
HTTPServer *httpserver;
|
||||
} Instance;
|
||||
|
||||
static void _print_usage ()
|
||||
{
|
||||
cout << "Usage: udpt [<configuration file>]" << endl;
|
||||
}
|
||||
|
||||
static void _doAPIStart (Settings *settings, WebApp **wa, HTTPServer **srv, DatabaseDriver *drvr)
|
||||
{
|
||||
if (settings == NULL)
|
||||
return;
|
||||
Settings::SettingClass *sc = settings->getClass("apiserver");
|
||||
if (sc == NULL)
|
||||
return; // no settings set!
|
||||
|
||||
if (!sc->getBool("enable", false))
|
||||
{
|
||||
cerr << "API Server not enabled." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
*srv = Instance.httpserver = new HTTPServer (settings);
|
||||
*wa = Instance.wa = new WebApp (*srv, drvr, settings);
|
||||
(*wa)->deploy();
|
||||
} catch (ServerException &e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
UDPT::Logger *logger = NULL;
|
||||
|
||||
static void _signal_handler(int sig)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "Signal " << sig << " raised. Terminating...";
|
||||
logger->log(Logger::LL_INFO, ss.str());
|
||||
_doCleanup();
|
||||
switch (sig)
|
||||
{
|
||||
case SIGTERM:
|
||||
UDPT::Tracker::getInstance().stop();
|
||||
break;
|
||||
case SIGHUP:
|
||||
// TODO: Reload config.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
static void daemonize(const boost::program_options::variables_map& conf)
|
||||
{
|
||||
if (1 == ::getppid()) return; // already a daemon
|
||||
int r = ::fork();
|
||||
if (0 > r) ::exit(-1); // failed to daemonize.
|
||||
if (0 < r) ::exit(0); // parent exists.
|
||||
|
||||
::umask(0);
|
||||
::setsid();
|
||||
|
||||
// close all fds.
|
||||
for (int i = ::getdtablesize(); i >=0; --i)
|
||||
{
|
||||
::close(i);
|
||||
}
|
||||
|
||||
::chdir(conf["daemon.chdir"].as<std::string>().c_str());
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Settings *settings;
|
||||
UDPTracker *usi;
|
||||
string config_file;
|
||||
int r;
|
||||
Tracker& tracker = UDPT::Tracker::getInstance();
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||
::WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||
#endif
|
||||
|
||||
cout << "UDP Tracker (UDPT) " << VERSION << " (" << PLATFORM << ")" << endl;
|
||||
cout << "Copyright 2012,2013 Naim Abda <naim94a@gmail.com>\n\tReleased under the GPLv3 License." << endl;
|
||||
cout << "Build Date: " << __DATE__ << endl << endl;
|
||||
boost::program_options::options_description commandLine("Command line options");
|
||||
commandLine.add_options()
|
||||
("help,h", "produce help message")
|
||||
("all-help", "displays all help")
|
||||
("test,t", "test configuration file")
|
||||
("config,c", boost::program_options::value<std::string>()->default_value("/etc/udpt.conf"), "configuration file to use")
|
||||
#ifdef linux
|
||||
("interactive,i", "doesn't start as daemon")
|
||||
#endif
|
||||
;
|
||||
|
||||
config_file = "udpt.conf";
|
||||
memset(&Instance, 0, sizeof(Instance));
|
||||
boost::program_options::options_description configOptions("Configuration options");
|
||||
configOptions.add_options()
|
||||
("db.driver", boost::program_options::value<std::string>()->default_value("sqlite3"), "database driver to use")
|
||||
("db.param", boost::program_options::value<std::string>()->default_value("/var/lib/udpt.db"), "database connection parameters")
|
||||
|
||||
#ifdef SIGBREAK
|
||||
signal(SIGBREAK, &_signal_handler);
|
||||
("tracker.is_dynamic", boost::program_options::value<bool>()->default_value(true), "Sets if the tracker is dynamic")
|
||||
("tracker.port", boost::program_options::value<unsigned short>()->default_value(6969), "UDP port to listen on")
|
||||
("tracker.threads", boost::program_options::value<unsigned>()->default_value(5), "threads to run (UDP only)")
|
||||
("tracker.allow_remotes", boost::program_options::value<bool>()->default_value(true), "allows clients to report remote IPs")
|
||||
("tracker.allow_iana_ips", boost::program_options::value<bool>()->default_value(false), "allows IANA reserved IPs to connect (useful for debugging)")
|
||||
("tracker.announce_interval", boost::program_options::value<unsigned>()->default_value(1800), "announce interval")
|
||||
("tracker.cleanup_interval", boost::program_options::value<unsigned>()->default_value(120), "sets database cleanup interval")
|
||||
|
||||
("apiserver.enable", boost::program_options::value<bool>()->default_value(0), "Enable API server?")
|
||||
("apiserver.threads", boost::program_options::value<unsigned>()->default_value(1), "threads for API server")
|
||||
("apiserver.port", boost::program_options::value<unsigned short>()->default_value(6969), "TCP port to listen on")
|
||||
|
||||
("logging.filename", boost::program_options::value<std::string>()->default_value("stdout"), "file to write logs to")
|
||||
("logging.level", boost::program_options::value<std::string>()->default_value("warning"), "log level (error/warning/info/debug)")
|
||||
|
||||
#ifdef linux
|
||||
("daemon.chdir", boost::program_options::value<std::string>()->default_value("/"), "home directory for daemon")
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
signal(SIGTERM, &_signal_handler);
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
signal(SIGABRT, &_signal_handler);
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
signal(SIGINT, &_signal_handler);
|
||||
;
|
||||
|
||||
boost::program_options::variables_map var_map;
|
||||
boost::program_options::store(boost::program_options::parse_command_line(argc, argv, commandLine), var_map);
|
||||
boost::program_options::notify(var_map);
|
||||
|
||||
if (var_map.count("help"))
|
||||
{
|
||||
std::cout << "UDP Tracker (UDPT) " << VERSION << " (" << PLATFORM << ")" << std::endl
|
||||
<< "Copyright 2012-2016 Naim A. <naim94a@gmail.com>" << std::endl
|
||||
<< "Build Date: " << __DATE__ << std::endl << std::endl;
|
||||
|
||||
std::cout << commandLine << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (var_map.count("all-help"))
|
||||
{
|
||||
std::cout << commandLine << std::endl;
|
||||
std::cout << configOptions << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string config_filename(var_map["config"].as<std::string>());
|
||||
bool isTest = (0 != var_map.count("test"));
|
||||
|
||||
if (var_map.count("config"))
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::program_options::basic_parsed_options<wchar_t> parsed_options = boost::program_options::parse_config_file<wchar_t>(config_filename.c_str(), configOptions);
|
||||
boost::program_options::store(
|
||||
parsed_options,
|
||||
var_map);
|
||||
}
|
||||
catch (const boost::program_options::error& ex)
|
||||
{
|
||||
std::cerr << "ERROR: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isTest)
|
||||
{
|
||||
std::cout << "Config OK" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UDPT::Logger> spLogger;
|
||||
try
|
||||
{
|
||||
spLogger = std::shared_ptr<UDPT::Logger>(new UDPT::Logger(var_map));
|
||||
logger = spLogger.get();
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
std::cerr << "Failed to initialize logger: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
if (!var_map.count("interactive"))
|
||||
{
|
||||
daemonize(var_map);
|
||||
}
|
||||
::signal(SIGHUP, _signal_handler);
|
||||
::signal(SIGTERM, _signal_handler);
|
||||
#endif
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
// set current directory when no filename is present.
|
||||
_setCWD(argv[0]);
|
||||
|
||||
_print_usage ();
|
||||
}
|
||||
else if (argc >= 2)
|
||||
{
|
||||
config_file = argv[1]; // reported in issue #5.
|
||||
}
|
||||
|
||||
settings = Instance.settings = new Settings (config_file);
|
||||
|
||||
if (!settings->load())
|
||||
{
|
||||
const char strDATABASE[] = "database";
|
||||
const char strTRACKER[] = "tracker";
|
||||
const char strAPISRV [] = "apiserver";
|
||||
// set default settings:
|
||||
|
||||
settings->set (strDATABASE, "driver", "sqlite3");
|
||||
settings->set (strDATABASE, "file", "tracker.db");
|
||||
|
||||
settings->set (strTRACKER, "is_dynamic", "0");
|
||||
settings->set (strTRACKER, "port", "6969"); // UDP PORT
|
||||
settings->set (strTRACKER, "threads", "5");
|
||||
settings->set (strTRACKER, "allow_remotes", "1");
|
||||
settings->set (strTRACKER, "allow_iana_ips", "1");
|
||||
settings->set (strTRACKER, "announce_interval", "1800");
|
||||
settings->set (strTRACKER, "cleanup_interval", "120");
|
||||
|
||||
settings->set (strAPISRV, "enable", "1");
|
||||
settings->set (strAPISRV, "threads", "1");
|
||||
settings->set (strAPISRV, "port", "6969"); // TCP PORT
|
||||
|
||||
settings->save();
|
||||
cerr << "Failed to read from '" << config_file.c_str() << "'. Using default settings." << endl;
|
||||
}
|
||||
|
||||
logger = new Logger (settings);
|
||||
usi = Instance.usi = new UDPTracker (settings);
|
||||
|
||||
HTTPServer *apiSrv = NULL;
|
||||
WebApp *wa = NULL;
|
||||
|
||||
r = usi->start();
|
||||
if (r != UDPTracker::START_OK)
|
||||
{
|
||||
cerr << "Error While trying to start server." << endl;
|
||||
switch (r)
|
||||
{
|
||||
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;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
_doAPIStart(settings, &wa, &apiSrv, usi->conn);
|
||||
|
||||
cout << "Hit Control-C to exit." << endl;
|
||||
|
||||
usi->wait();
|
||||
|
||||
cleanup:
|
||||
cout << endl << "Goodbye." << endl;
|
||||
tracker.start(var_map);
|
||||
tracker.wait();
|
||||
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
::WSACleanup();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -28,7 +28,7 @@
|
|||
#define linux
|
||||
#endif
|
||||
|
||||
#define VERSION "1.0.0-beta"
|
||||
#define VERSION "1.0.2-dev"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
|
@ -36,11 +36,13 @@
|
|||
#elif defined (linux)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET 0
|
||||
|
|
451
src/settings.cpp
451
src/settings.cpp
|
@ -1,451 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 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);
|
||||
|
||||
// printf("KEY: '%s'\tVALUE: '%s'\n", key, 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;
|
||||
}
|
||||
};
|
169
src/settings.hpp
169
src/settings.hpp
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 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);
|
||||
};
|
||||
};
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
//
|
||||
//typedef struct {
|
||||
// char *key;
|
||||
// char *values;
|
||||
//} KeyValue;
|
||||
//
|
||||
//typedef struct {
|
||||
// char *classname;
|
||||
// KeyValue *entries;
|
||||
// uint32_t entry_count, entry_size;
|
||||
//} SettingClass;
|
||||
//
|
||||
//typedef struct {
|
||||
// char *filename;
|
||||
//
|
||||
// SettingClass *classes;
|
||||
// uint32_t class_count, class_size;
|
||||
//
|
||||
// char *buffer;
|
||||
//} Settings;
|
||||
//
|
||||
//
|
||||
//void settings_init (Settings *s, const char *filename);
|
||||
//
|
||||
//int settings_load (Settings *s);
|
||||
//
|
||||
//int settings_save (Settings *s);
|
||||
//
|
||||
//void settings_destroy (Settings *s);
|
||||
//
|
||||
//SettingClass* settings_get_class (Settings *s, const char *classname);
|
||||
//
|
||||
//char* settingclass_get (SettingClass *s, const char *name);
|
||||
//
|
||||
//int settingclass_set (SettingClass *s, const char *name, const char *value);
|
||||
//
|
||||
//char* settings_get (Settings *s, const char *classn, const char *name);
|
||||
//
|
||||
//
|
||||
//int settings_set (Settings *s, const char *classn, const char *name, const char *value);
|
||||
//
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
50
src/tracker.cpp
Normal file
50
src/tracker.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "tracker.hpp"
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
Tracker::Tracker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Tracker::~Tracker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Tracker::stop()
|
||||
{
|
||||
m_udpTracker->stop();
|
||||
wait();
|
||||
|
||||
m_apiSrv = nullptr;
|
||||
m_webApp = nullptr;
|
||||
m_udpTracker = nullptr;
|
||||
}
|
||||
|
||||
void Tracker::wait()
|
||||
{
|
||||
m_udpTracker->wait();
|
||||
}
|
||||
|
||||
void Tracker::start(const boost::program_options::variables_map& conf)
|
||||
{
|
||||
m_udpTracker = std::shared_ptr<UDPTracker>(new UDPTracker(conf));
|
||||
|
||||
if (conf["apiserver.enable"].as<bool>())
|
||||
{
|
||||
m_apiSrv = std::shared_ptr<UDPT::Server::HTTPServer>(new UDPT::Server::HTTPServer(conf));
|
||||
m_webApp = std::shared_ptr<UDPT::Server::WebApp>(new UDPT::Server::WebApp(m_apiSrv, m_udpTracker->m_conn.get(), conf));
|
||||
m_webApp->deploy();
|
||||
}
|
||||
|
||||
m_udpTracker->start();
|
||||
}
|
||||
|
||||
Tracker& Tracker::getInstance()
|
||||
{
|
||||
static Tracker s_tracker;
|
||||
|
||||
return s_tracker;
|
||||
}
|
||||
}
|
35
src/tracker.hpp
Normal file
35
src/tracker.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "logging.h"
|
||||
#include "multiplatform.h"
|
||||
#include "udpTracker.hpp"
|
||||
#include "http/httpserver.hpp"
|
||||
#include "http/webapp.hpp"
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
class Tracker
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Tracker();
|
||||
|
||||
void stop();
|
||||
|
||||
void start(const boost::program_options::variables_map& conf);
|
||||
|
||||
void wait();
|
||||
|
||||
static Tracker& getInstance();
|
||||
|
||||
private:
|
||||
std::shared_ptr<UDPT::UDPTracker> m_udpTracker;
|
||||
std::shared_ptr<UDPT::Server::HTTPServer> m_apiSrv;
|
||||
std::shared_ptr<UDPT::Server::WebApp> m_webApp;
|
||||
|
||||
Tracker();
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -17,174 +17,145 @@
|
|||
* 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
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
UDPTracker::UDPTracker (Settings *settings)
|
||||
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf)
|
||||
{
|
||||
Settings::SettingClass *sc_tracker;
|
||||
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>();
|
||||
|
||||
sc_tracker = settings->getClass("tracker");
|
||||
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;
|
||||
|
||||
this->allowRemotes = sc_tracker->getBool("allow_remotes", true);
|
||||
this->allowIANA_IPs = sc_tracker->getBool("allow_iana_ips", false);
|
||||
this->isDynamic = sc_tracker->getBool("is_dynamic", true);
|
||||
|
||||
this->announce_interval = sc_tracker->getInt("announce_interval", 1800);
|
||||
this->cleanup_interval = sc_tracker->getInt("cleanup_interval", 120);
|
||||
this->port = sc_tracker->getInt("port", 6969);
|
||||
this->thread_count = abs (sc_tracker->getInt("threads", 5)) + 1;
|
||||
|
||||
list<SOCKADDR_IN> addrs;
|
||||
sc_tracker->getIPs("bind", 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->threads = new HANDLE[this->thread_count];
|
||||
|
||||
this->isRunning = false;
|
||||
this->conn = NULL;
|
||||
this->o_settings = settings;
|
||||
this->m_localEndpoint = addrs.front();
|
||||
}
|
||||
|
||||
UDPTracker::~UDPTracker()
|
||||
{
|
||||
int i; // loop index
|
||||
|
||||
this->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);
|
||||
|
||||
sleep (1);
|
||||
#elif defined (WIN32)
|
||||
closesocket (this->sock);
|
||||
|
||||
Sleep (1000);
|
||||
#endif
|
||||
|
||||
for (i = 0;i < this->thread_count;i++)
|
||||
{
|
||||
#ifdef WIN32
|
||||
TerminateThread (this->threads[i], 0x00);
|
||||
#elif defined (linux)
|
||||
pthread_detach (this->threads[i]);
|
||||
pthread_cancel (this->threads[i]);
|
||||
#endif
|
||||
stringstream str;
|
||||
str << "Thread (" << (i + 1) << "/" << ((int)this->thread_count) << ") terminated.";
|
||||
logger->log(Logger::LL_INFO, str.str());
|
||||
}
|
||||
if (this->conn != NULL)
|
||||
delete this->conn;
|
||||
delete[] this->threads;
|
||||
stop();
|
||||
}
|
||||
|
||||
void UDPTracker::wait()
|
||||
void UDPTracker::start()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WaitForMultipleObjects(this->thread_count, this->threads, TRUE, INFINITE);
|
||||
#else
|
||||
int i;
|
||||
for (i = 0;i < this->thread_count; i++)
|
||||
{
|
||||
pthread_join (this->threads[i], NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
enum UDPTracker::StartStatus 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);
|
||||
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);
|
||||
::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));
|
||||
{
|
||||
// don't block recvfrom for too long.
|
||||
#if defined(linux)
|
||||
timeval timeout = { 0 };
|
||||
timeout.tv_sec = 5;
|
||||
#elif defined(WIN32)
|
||||
DWORD timeout = 5000;
|
||||
#else
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
::setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeout), sizeof(timeout));
|
||||
}
|
||||
|
||||
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 (this->o_settings->getClass("database"),
|
||||
this->isDynamic);
|
||||
|
||||
this->isRunning = true;
|
||||
this->m_conn = std::shared_ptr<DatabaseDriver>(new Data::SQLite3Driver(m_conf, this->m_isDynamic));
|
||||
|
||||
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);
|
||||
#elif defined (linux)
|
||||
pthread_create (&this->threads[0], NULL, _maintainance_start, (void*)this);
|
||||
#endif
|
||||
|
||||
for (i = 1;i < this->thread_count; i++)
|
||||
m_threads.push_back(boost::thread(UDPTracker::_maintainance_start, this));
|
||||
|
||||
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);
|
||||
#elif defined (linux)
|
||||
pthread_create (&(this->threads[i]), NULL, _thread_start, (void*)this);
|
||||
m_threads.push_back(boost::thread(UDPTracker::_thread_start, this));
|
||||
}
|
||||
}
|
||||
|
||||
void UDPTracker::stop()
|
||||
{
|
||||
#ifdef linux
|
||||
::close(m_sock);
|
||||
#elif defined (WIN32)
|
||||
::closesocket(m_sock);
|
||||
#endif
|
||||
|
||||
for (std::vector<boost::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
it->interrupt();
|
||||
}
|
||||
|
||||
return START_OK;
|
||||
wait();
|
||||
}
|
||||
|
||||
int UDPTracker::sendError (UDPTracker *usi, SOCKADDR_IN *remote, uint32_t transactionID, const string &msg)
|
||||
void UDPTracker::wait()
|
||||
{
|
||||
for (std::vector<boost::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
it->join();
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -201,35 +172,33 @@ 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;
|
||||
|
||||
if (!usi->conn->genConnectionId(&resp.connection_id,
|
||||
if (!usi->m_conn->genConnectionId(&resp.connection_id,
|
||||
m_hton32(remote->sin_addr.s_addr),
|
||||
m_hton16(remote->sin_port)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -248,7 +217,7 @@ namespace UDPT
|
|||
|
||||
req = (AnnounceRequest*)data;
|
||||
|
||||
if (!usi->conn->verifyConnectionId(req->connection_id,
|
||||
if (!usi->m_conn->verifyConnectionId(req->connection_id,
|
||||
m_hton32(remote->sin_addr.s_addr),
|
||||
m_hton16(remote->sin_port)))
|
||||
{
|
||||
|
@ -264,13 +233,13 @@ 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;
|
||||
}
|
||||
|
||||
if (!usi->conn->isTorrentAllowed(req->info_hash))
|
||||
if (!usi->m_conn->isTorrentAllowed(req->info_hash))
|
||||
{
|
||||
UDPTracker::sendError(usi, remote, req->transaction_id, "info_hash not registered.");
|
||||
return 0;
|
||||
|
@ -279,7 +248,7 @@ namespace UDPT
|
|||
// load peers
|
||||
q = 30;
|
||||
if (req->num_want >= 1)
|
||||
q = min (q, req->num_want);
|
||||
q = std::min<int>(q, req->num_want);
|
||||
|
||||
peers = new DatabaseDriver::PeerEntry [q];
|
||||
|
||||
|
@ -305,17 +274,17 @@ namespace UDPT
|
|||
q = 0; // no need for peers when stopping.
|
||||
|
||||
if (q > 0)
|
||||
usi->conn->getPeers(req->info_hash, &q, peers);
|
||||
usi->m_conn->getPeers(req->info_hash, &q, peers);
|
||||
|
||||
bSize = 20; // header is 20 bytes
|
||||
bSize += (6 * q); // + 6 bytes per peer.
|
||||
|
||||
tE.info_hash = req->info_hash;
|
||||
usi->conn->getTorrentInfo(&tE);
|
||||
usi->m_conn->getTorrentInfo(&tE);
|
||||
|
||||
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;
|
||||
|
@ -337,7 +306,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;
|
||||
|
@ -345,7 +314,7 @@ namespace UDPT
|
|||
ip = m_hton32 (remote->sin_addr.s_addr);
|
||||
else
|
||||
ip = req->ip_address;
|
||||
usi->conn->updatePeer(req->peer_id, req->info_hash, ip, req->port,
|
||||
usi->m_conn->updatePeer(req->peer_id, req->info_hash, ip, req->port,
|
||||
req->downloaded, req->left, req->uploaded, event);
|
||||
|
||||
return 0;
|
||||
|
@ -353,7 +322,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
|
||||
|
@ -362,9 +331,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)
|
||||
|
@ -373,7 +339,7 @@ namespace UDPT
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!usi->conn->verifyConnectionId(sR->connection_id,
|
||||
if (!usi->m_conn->verifyConnectionId(sR->connection_id,
|
||||
m_hton32(remote->sin_addr.s_addr),
|
||||
m_hton16(remote->sin_port)))
|
||||
{
|
||||
|
@ -383,7 +349,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;
|
||||
|
||||
|
@ -402,7 +368,7 @@ namespace UDPT
|
|||
|
||||
DatabaseDriver::TorrentEntry tE;
|
||||
tE.info_hash = hash;
|
||||
if (!usi->conn->getTorrentInfo(&tE))
|
||||
if (!usi->m_conn->getTorrentInfo(&tE))
|
||||
{
|
||||
sendError(usi, remote, sR->transaction_id, "Scrape Failed: couldn't retrieve torrent data");
|
||||
return 0;
|
||||
|
@ -413,12 +379,12 @@ 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;
|
||||
}
|
||||
|
||||
static int _isIANA_IP (uint32_t ip)
|
||||
int UDPTracker::isIANAIP(uint32_t ip)
|
||||
{
|
||||
uint8_t x = (ip % 256);
|
||||
if (x == 0 || x == 10 || x == 127 || x >= 224)
|
||||
|
@ -428,23 +394,19 @@ 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))
|
||||
if (isIANAIP(remote->sin_addr.s_addr))
|
||||
{
|
||||
return 0; // Access Denied: IANA reserved IP.
|
||||
}
|
||||
}
|
||||
|
||||
// cout << ":: " << (void*)m_hton32(remote->sin_addr.s_addr) << ": " << m_hton16(remote->sin_port) << " ACTION=" << action << endl;
|
||||
|
||||
if (action == 0 && r >= 16)
|
||||
return UDPTracker::handleConnection(usi, remote, data);
|
||||
else if (action == 1 && r >= 98)
|
||||
|
@ -453,7 +415,6 @@ static int _isIANA_IP (uint32_t ip)
|
|||
return UDPTracker::handleScrape(usi, remote, data, r);
|
||||
else
|
||||
{
|
||||
// cout << "E: action=" << action << ", r=" << r << endl;
|
||||
UDPTracker::sendError(usi, remote, cR->transaction_id, "Tracker couldn't understand Client's request.");
|
||||
return -1;
|
||||
}
|
||||
|
@ -461,14 +422,10 @@ static int _isIANA_IP (uint32_t ip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD UDPTracker::_thread_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
void* UDPTracker::_thread_start (void *arg)
|
||||
#endif
|
||||
void UDPTracker::_thread_start(UDPTracker *usi)
|
||||
{
|
||||
UDPTracker *usi;
|
||||
SOCKADDR_IN remoteAddr;
|
||||
char tmpBuff[UDP_BUFFER_SIZE];
|
||||
|
||||
#ifdef linux
|
||||
socklen_t addrSz;
|
||||
|
@ -476,54 +433,37 @@ static int _isIANA_IP (uint32_t ip)
|
|||
int addrSz;
|
||||
#endif
|
||||
|
||||
int r;
|
||||
char tmpBuff [UDP_BUFFER_SIZE];
|
||||
|
||||
usi = (UDPTracker*)arg;
|
||||
|
||||
addrSz = sizeof(SOCKADDR_IN);
|
||||
|
||||
|
||||
while (usi->isRunning)
|
||||
while (true)
|
||||
{
|
||||
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);
|
||||
int r = ::recvfrom(usi->m_sock, (char*)tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
|
||||
if (r <= 0)
|
||||
continue; // bad request...
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
boost::this_thread::disable_interruption di;
|
||||
r = UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r);
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
pthread_exit (NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD UDPTracker::_maintainance_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
void* UDPTracker::_maintainance_start (void *arg)
|
||||
#endif
|
||||
void UDPTracker::_maintainance_start(UDPTracker* usi)
|
||||
{
|
||||
UDPTracker *usi;
|
||||
|
||||
usi = (UDPTracker *)arg;
|
||||
|
||||
while (usi->isRunning)
|
||||
while (true)
|
||||
{
|
||||
usi->conn->cleanup();
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep (usi->cleanup_interval * 1000);
|
||||
#elif defined (linux)
|
||||
sleep (usi->cleanup_interval);
|
||||
#else
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
{
|
||||
boost::this_thread::disable_interruption di;
|
||||
usi->m_conn->cleanup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(usi->m_cleanupInterval));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -22,17 +22,19 @@
|
|||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <boost/thread.hpp>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <string>
|
||||
#include "exceptions.h"
|
||||
#include "multiplatform.h"
|
||||
#include "db/driver_sqlite.hpp"
|
||||
#include "settings.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
|
||||
|
@ -117,16 +119,20 @@ namespace UDPT
|
|||
* Initializes the UDP Tracker.
|
||||
* @param settings Settings to start server with
|
||||
*/
|
||||
UDPTracker (Settings *);
|
||||
UDPTracker(const boost::program_options::variables_map& conf);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Terminates tracker.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Joins worker threads
|
||||
*/
|
||||
void wait();
|
||||
|
||||
|
@ -136,29 +142,24 @@ namespace UDPT
|
|||
*/
|
||||
virtual ~UDPTracker();
|
||||
|
||||
Data::DatabaseDriver *conn;
|
||||
std::shared_ptr<UDPT::Data::DatabaseDriver> m_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_isDynamic;
|
||||
bool m_allowRemotes;
|
||||
bool m_allowIANA_IPs;
|
||||
std::vector<boost::thread> m_threads;
|
||||
uint32_t m_announceInterval;
|
||||
uint32_t m_cleanupInterval;
|
||||
|
||||
Settings *o_settings;
|
||||
const boost::program_options::variables_map& m_conf;
|
||||
|
||||
#ifdef WIN32
|
||||
static DWORD _thread_start (LPVOID arg);
|
||||
static DWORD _maintainance_start (LPVOID arg);
|
||||
#elif defined (linux)
|
||||
static void* _thread_start (void *arg);
|
||||
static void* _maintainance_start (void *arg);
|
||||
#endif
|
||||
static void _thread_start(UDPTracker *usi);
|
||||
static void _maintainance_start(UDPTracker* usi);
|
||||
|
||||
static int resolveRequest(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r);
|
||||
|
||||
|
@ -166,8 +167,9 @@ 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 &);
|
||||
|
||||
static int isIANAIP(uint32_t ip);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue