diff --git a/.gitignore b/.gitignore index 5761abc..8c483d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.o +*.sublime-* diff --git a/Makefile b/Makefile index 0de727a..9b37e76 100644 --- a/Makefile +++ b/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... diff --git a/README b/README deleted file mode 100644 index a941a6a..0000000 --- a/README +++ /dev/null @@ -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. . 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 - diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5f8604 --- /dev/null +++ b/README.md @@ -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. + +
+    $ git clone https://github.com/naim94a/udpt.git
+    $ cd udpt
+    $ make
+
+ +And finally: + +
+    $ ./udpt
+
+ +### 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. diff --git a/src/db/database.cpp b/src/db/database.cpp index a521a9f..1df5798 100644 --- a/src/db/database.cpp +++ b/src/db/database.cpp @@ -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; } diff --git a/src/db/database.hpp b/src/db/database.hpp index ac4f9e5..878da73 100644 --- a/src/db/database.hpp +++ b/src/db/database.hpp @@ -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 namespace UDPT { @@ -35,10 +35,10 @@ namespace UDPT E_CONNECTION_FAILURE = 2 }; - DatabaseException (); - DatabaseException (EType); - EType getErrorType (); - const char* getErrorMessage (); + DatabaseException(); + DatabaseException(EType); + EType getErrorType(); + const char* getErrorMessage(); private: EType errorNum; }; @@ -68,34 +68,34 @@ 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. * @param hash The info_hash of the torrent. * @return true on success. false on failure. */ - virtual bool addTorrent (uint8_t hash[20]); + virtual bool addTorrent(uint8_t hash[20]); /** * Removes a torrent from the database. should be used only for non-dynamic trackers or by cleanup. * @param hash The info_hash to drop. * @return true if torrent's database was dropped or no longer exists. otherwise false (shouldn't happen - critical) */ - virtual bool removeTorrent (uint8_t hash[20]); + virtual bool removeTorrent(uint8_t hash[20]); /** * Checks if the Database is acting as a dynamic tracker DB. * @return true if dynamic. otherwise false. */ - bool isDynamic (); + bool isDynamic(); /** * Checks if the torrent can be used in the tracker. * @param info_hash The torrent's info_hash. * @return true if allowed. otherwise false. */ - virtual bool isTorrentAllowed (uint8_t info_hash [20]); + virtual bool isTorrentAllowed(uint8_t info_hash [20]); /** * Generate a Connection ID for the peer. @@ -104,9 +104,9 @@ namespace UDPT * @param port The peer's IP (remote port if tracker accepts) * @return */ - virtual bool genConnectionId (uint64_t *connectionId, uint32_t ip, uint16_t port); + virtual bool genConnectionId(uint64_t *connectionId, uint32_t ip, uint16_t port); - virtual bool verifyConnectionId (uint64_t connectionId, uint32_t ip, uint16_t port); + virtual bool verifyConnectionId(uint64_t connectionId, uint32_t ip, uint16_t port); /** * Updates/Adds a peer to/in the database. @@ -119,7 +119,7 @@ namespace UDPT * @param uploaded total bytes uploaded * @return true on success, false on failure. */ - virtual bool updatePeer (uint8_t peer_id [20], uint8_t info_hash [20], + virtual bool updatePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port, int64_t downloaded, int64_t left, int64_t uploaded, enum TrackerEvents event); @@ -132,14 +132,14 @@ namespace UDPT * @param port The TCP port (remote port if tracker accepts) * @return true on success. false on failure (shouldn't happen - critical) */ - virtual bool removePeer (uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port); + virtual bool removePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port); /** * Gets stats on a torrent * @param e TorrentEntry, only this info_hash has to be set * @return true on success, false on failure. */ - virtual bool getTorrentInfo (TorrentEntry *e); + virtual bool getTorrentInfo(TorrentEntry *e); /** * Gets a list of peers from the database. @@ -148,21 +148,21 @@ namespace UDPT * @param pe The list of peers. Must be pre-allocated to the size of max_count. * @return true on success, otherwise false (shouldn't happen). */ - virtual bool getPeers (uint8_t info_hash [20], int *max_count, PeerEntry *pe); + virtual bool getPeers(uint8_t info_hash [20], int *max_count, PeerEntry *pe); /** * Cleanup the database. * Other actions may be locked when using this depending on the driver. */ - virtual void cleanup (); + virtual void cleanup(); /** * Closes the connections, and releases all other resources. */ - virtual ~DatabaseDriver (); + virtual ~DatabaseDriver(); protected: - Settings::SettingClass *dClass; + const boost::program_options::variables_map& m_conf; private: bool is_dynamic; }; diff --git a/src/db/driver_sqlite.cpp b/src/db/driver_sqlite.cpp index 9601420..cf8bc65 100644 --- a/src/db/driver_sqlite.cpp +++ b/src/db/driver_sqlite.cpp @@ -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(); 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); diff --git a/src/db/driver_sqlite.hpp b/src/db/driver_sqlite.hpp index 34b28d9..048abbc 100644 --- a/src/db/driver_sqlite.hpp +++ b/src/db/driver_sqlite.hpp @@ -1,5 +1,5 @@ /* - * Copyright © 2012,2013 Naim A. + * Copyright © 2012-2016 Naim A. * * This file is part of UDPT. * @@ -31,23 +31,23 @@ namespace UDPT class SQLite3Driver : public DatabaseDriver { public: - SQLite3Driver (Settings::SettingClass *sc, 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); - bool verifyConnectionId (uint64_t connId, uint32_t ip, uint16_t port); - bool updatePeer (uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port, int64_t downloaded, int64_t left, int64_t uploaded, enum TrackerEvents event); - bool removePeer (uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port); - bool getTorrentInfo (TorrentEntry *e); - bool isTorrentAllowed (uint8_t info_hash[20]); - bool getPeers (uint8_t info_hash [20], int *max_count, PeerEntry *pe); - void cleanup (); + 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); + bool verifyConnectionId(uint64_t connId, uint32_t ip, uint16_t port); + bool updatePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port, int64_t downloaded, int64_t left, int64_t uploaded, enum TrackerEvents event); + bool removePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port); + bool getTorrentInfo(TorrentEntry *e); + bool isTorrentAllowed(uint8_t info_hash[20]); + bool getPeers(uint8_t info_hash [20], int *max_count, PeerEntry *pe); + void cleanup(); - ~SQLite3Driver (); + virtual ~SQLite3Driver(); private: sqlite3 *db; - void doSetup (); + void doSetup(); }; }; }; diff --git a/src/exceptions.h b/src/exceptions.h new file mode 100644 index 0000000..43e14b4 --- /dev/null +++ b/src/exceptions.h @@ -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; + }; +} diff --git a/src/http/httpserver.cpp b/src/http/httpserver.cpp index c8d774f..27ac298 100644 --- a/src/http/httpserver.cpp +++ b/src/http/httpserver.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2013 Naim A. + * Copyright © 2013-2016 Naim A. * * This file is part of UDPT. * @@ -23,6 +23,7 @@ #include #include #include "httpserver.hpp" +#include using namespace std; @@ -43,26 +44,18 @@ 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 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(); + threads = conf["apiserver.threads"].as(); if (threads <= 0) threads = 1; - + if (localEndpoints.empty()) { SOCKADDR_IN sa; @@ -85,16 +78,16 @@ 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"); + throw ServerException(2, "Failed to bind socket"); } this->isRunning = true; @@ -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 << ""; stream << "Not Found"; - stream << "

Not Found

The server couldn't find the request resource.


© 2013 Naim A. | The UDPT Project
"; + stream << "

Not Found

The server couldn't find the request resource.


"; stream << ""; string str = stream.str(); resp.write (str.c_str(), str.length()); @@ -183,7 +176,7 @@ doSrv: stringstream stream; stream << ""; stream << "Internal Server Error"; - stream << "

Internal Server Error

An Error Occurred while trying to process your request.


© 2013 Naim A. | The UDPT Project
"; + stream << "

Internal Server Error

An Error Occurred while trying to process your request.


"; stream << ""; string str = stream.str(); resp.write (str.c_str(), str.length()); diff --git a/src/http/httpserver.hpp b/src/http/httpserver.hpp index e4b1d16..45d48a9 100644 --- a/src/http/httpserver.hpp +++ b/src/http/httpserver.hpp @@ -1,5 +1,5 @@ /* - * Copyright © 2013 Naim A. + * Copyright © 2013-2016 Naim A. * * This file is part of UDPT. * @@ -24,8 +24,8 @@ #include #include #include +#include #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 *path, reqCallback *); diff --git a/src/http/webapp.cpp b/src/http/webapp.cpp index 4f2f870..3ab1c03 100644 --- a/src/http/webapp.cpp +++ b/src/http/webapp.cpp @@ -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 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* aK = apiKeys->getMap(); - map::iterator it, end; - end = aK->end(); - for (it = aK->begin();it != end;it++) - { - string key = it->first; - list 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 >(key, ips)); - } - - } - - srv->setData("webapp", this); + m_server->setData("webapp", this); } WebApp::~WebApp() @@ -136,29 +112,24 @@ namespace UDPT void WebApp::deploy() { list 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) + void WebApp::handleRoot(HTTPServer *srv, HTTPServer::Request *req, HTTPServer::Response *resp) { // It would be very appreciated to keep this in the code. resp->write("" - "Powered by UDPT" + "UDPT Torrent Tracker" "" - "

The UDPT Project

" - "
This tracker is running on UDPT Software.
" - "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: http://code.googe.com/p/udpt." - "

If you would like to help the project grow, please donate for our hard work, effort & time: " - "\"Donate" - "
" - "

© 2013 Naim A. | Powered by UDPT
" + "
This tracker is running on UDPT Software.
" + "

" "" ""); } @@ -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") diff --git a/src/http/webapp.hpp b/src/http/webapp.hpp index 6a8011f..dc4bafb 100644 --- a/src/http/webapp.hpp +++ b/src/http/webapp.hpp @@ -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 #include #include +#include +#include using namespace std; using namespace UDPT; @@ -37,15 +38,15 @@ namespace UDPT class WebApp { public: - WebApp (HTTPServer *, DatabaseDriver *, Settings *); - ~WebApp (); + WebApp(std::shared_ptr , DatabaseDriver *, const boost::program_options::variables_map& conf); + virtual ~WebApp(); void deploy (); private: - HTTPServer *instance; + std::shared_ptr m_server; UDPT::Data::DatabaseDriver *db; - Settings::SettingClass *sc_api; + const boost::program_options::variables_map& m_conf; std::map > ip_whitelist; static void handleRoot (HTTPServer*,HTTPServer::Request*, HTTPServer::Response*); diff --git a/src/logging.cpp b/src/logging.cpp index 80ef946..4266c73 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -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(); + const std::string& level = s["logging.level"].as(); 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"; } diff --git a/src/logging.h b/src/logging.h index 7d382ee..4ca37a9 100644 --- a/src/logging.h +++ b/src/logging.h @@ -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 #include #include #include +#include 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(const boost::program_options::variables_map& s); - Logger (Settings *s, ostream &os); + virtual ~Logger(); - 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); }; }; diff --git a/src/main.cpp b/src/main.cpp index 86c923a..c8bd11f 100644 --- a/src/main.cpp +++ b/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 -#include "logging.h" -#include "multiplatform.h" -#include "udpTracker.hpp" -#include "settings.hpp" -#include "http/httpserver.hpp" -#include "http/webapp.hpp" #include // atoi #include // signal #include // strlen +#include +#include -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; +UDPT::Logger *logger = NULL; -static void _print_usage () +static void _signal_handler(int sig) { - cout << "Usage: udpt []" << 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)) + switch (sig) { - 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; + case SIGTERM: + UDPT::Tracker::getInstance().stop(); + break; + case SIGHUP: + // TODO: Reload config. + break; } } -/** - * Sets current working directory to executables directory. - */ -static void _setCWD (char *argv0) +#ifdef linux +static void daemonize(const boost::program_options::variables_map& conf) { -#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); + 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. -#elif defined(linux) - int len, i; - char *strFN; - if (argv0 != NULL) - { - len = strlen (argv0); - strFN = new char [len + 1]; + ::umask(0); + ::setsid(); - for (i = len;i >= 0;i--) - { - if (strFN[i] == '/') - { - strFN = '\0'; - break; - } - } - chdir (strFN); - delete [] strFN; - } + // close all fds. + for (int i = ::getdtablesize(); i >=0; --i) + { + ::close(i); + } + + ::chdir(conf["daemon.chdir"].as().c_str()); + +} #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..."; - logger->log(Logger::LL_INFO, ss.str()); - _doCleanup(); -} - 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 \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()->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()->default_value("sqlite3"), "database driver to use") + ("db.param", boost::program_options::value()->default_value("/var/lib/udpt.db"), "database connection parameters") + + ("tracker.is_dynamic", boost::program_options::value()->default_value(true), "Sets if the tracker is dynamic") + ("tracker.port", boost::program_options::value()->default_value(6969), "UDP port to listen on") + ("tracker.threads", boost::program_options::value()->default_value(5), "threads to run (UDP only)") + ("tracker.allow_remotes", boost::program_options::value()->default_value(true), "allows clients to report remote IPs") + ("tracker.allow_iana_ips", boost::program_options::value()->default_value(false), "allows IANA reserved IPs to connect (useful for debugging)") + ("tracker.announce_interval", boost::program_options::value()->default_value(1800), "announce interval") + ("tracker.cleanup_interval", boost::program_options::value()->default_value(120), "sets database cleanup interval") + + ("apiserver.enable", boost::program_options::value()->default_value(0), "Enable API server?") + ("apiserver.threads", boost::program_options::value()->default_value(1), "threads for API server") + ("apiserver.port", boost::program_options::value()->default_value(6969), "TCP port to listen on") -#ifdef SIGBREAK - signal(SIGBREAK, &_signal_handler); -#endif -#ifdef SIGTERM - signal(SIGTERM, &_signal_handler); -#endif -#ifdef SIGABRT - signal(SIGABRT, &_signal_handler); -#endif -#ifdef SIGINT - signal(SIGINT, &_signal_handler); -#endif + ("logging.filename", boost::program_options::value()->default_value("stdout"), "file to write logs to") + ("logging.level", boost::program_options::value()->default_value("warning"), "log level (error/warning/info/debug)") - if (argc <= 1) +#ifdef linux + ("daemon.chdir", boost::program_options::value()->default_value("/"), "home directory for daemon") +#endif + ; + + 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")) { - // 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. + std::cout << "UDP Tracker (UDPT) " << VERSION << " (" << PLATFORM << ")" << std::endl + << "Copyright 2012-2016 Naim A. " << std::endl + << "Build Date: " << __DATE__ << std::endl << std::endl; + + std::cout << commandLine << std::endl; + return 0; } - settings = Instance.settings = new Settings (config_file); - - if (!settings->load()) + if (var_map.count("all-help")) { - 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; + std::cout << commandLine << std::endl; + std::cout << configOptions << std::endl; + return 0; } - logger = new Logger (settings); - usi = Instance.usi = new UDPTracker (settings); + std::string config_filename(var_map["config"].as()); + bool isTest = (0 != var_map.count("test")); - HTTPServer *apiSrv = NULL; - WebApp *wa = NULL; - - r = usi->start(); - if (r != UDPTracker::START_OK) + if (var_map.count("config")) { - 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; + boost::program_options::basic_parsed_options parsed_options = boost::program_options::parse_config_file(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; } - goto cleanup; } - _doAPIStart(settings, &wa, &apiSrv, usi->conn); + std::shared_ptr spLogger; + try + { + spLogger = std::shared_ptr(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; + } - cout << "Hit Control-C to exit." << endl; +#ifdef linux + if (!var_map.count("interactive")) + { + daemonize(var_map); + } + ::signal(SIGHUP, _signal_handler); + ::signal(SIGTERM, _signal_handler); +#endif - usi->wait(); - -cleanup: - cout << endl << "Goodbye." << endl; + tracker.start(var_map); + tracker.wait(); #ifdef WIN32 - WSACleanup(); + ::WSACleanup(); #endif return 0; diff --git a/src/multiplatform.h b/src/multiplatform.h index e03f9be..d837c9f 100644 --- a/src/multiplatform.h +++ b/src/multiplatform.h @@ -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 @@ -36,11 +36,13 @@ #elif defined (linux) #include #include +#include #include #include #include #include #include +#include #define SOCKET int #define INVALID_SOCKET 0 diff --git a/src/settings.cpp b/src/settings.cpp deleted file mode 100644 index ab7120f..0000000 --- a/src/settings.cpp +++ /dev/null @@ -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 . - */ - -#include "settings.hpp" -#include // still primitive - need for strlen() -#include // need for isspace() -#include -#include -#include -#include -#include "tools.h" - -using namespace std; - -namespace UDPT -{ - Settings::SettingClass* Settings::getClass(const string classname) - { - if (classname == "") - return NULL; - - map::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::iterator it; - for (it = this->classes.begin();it != this->classes.end();it++) - { - sclass = it->second; - cfg << "[" << it->first.c_str() << "]\n"; - - map::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::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(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 &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* Settings::SettingClass::getMap() - { - return &this->entries; - } - - bool Settings::SettingClass::set (const string name, const string value) - { - pair::iterator, bool> r; - r = this->entries.insert(pair(name, value)); - if (!r.second) - { - r.first->second = value; - } - - return true; - } -}; diff --git a/src/settings.hpp b/src/settings.hpp deleted file mode 100644 index 6c308e2..0000000 --- a/src/settings.hpp +++ /dev/null @@ -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 . - */ - -#pragma once - -#include -#include -#include -#include -#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* getMap (); - void getIPs (const string& key, list &ip); - private: - friend class Settings; - string className; - map 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 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 diff --git a/src/tools.c b/src/tools.c index e47098d..60faa2b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1,5 +1,5 @@ /* - * Copyright © 2012,2013 Naim A. + * Copyright © 2012-2016 Naim A. * * This file is part of UDPT. * diff --git a/src/tools.h b/src/tools.h index be0afc5..39b1840 100644 --- a/src/tools.h +++ b/src/tools.h @@ -1,5 +1,5 @@ /* - * Copyright © 2012,2013 Naim A. + * Copyright © 2012-2016 Naim A. * * This file is part of UDPT. * diff --git a/src/tracker.cpp b/src/tracker.cpp new file mode 100644 index 0000000..9cb7d68 --- /dev/null +++ b/src/tracker.cpp @@ -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(new UDPTracker(conf)); + + if (conf["apiserver.enable"].as()) + { + m_apiSrv = std::shared_ptr(new UDPT::Server::HTTPServer(conf)); + m_webApp = std::shared_ptr(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; + } +} diff --git a/src/tracker.hpp b/src/tracker.hpp new file mode 100644 index 0000000..0a0ea73 --- /dev/null +++ b/src/tracker.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#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 m_udpTracker; + std::shared_ptr m_apiSrv; + std::shared_ptr m_webApp; + + Tracker(); + }; +} diff --git a/src/udpTracker.cpp b/src/udpTracker.cpp index 2514868..dd6b5cd 100644 --- a/src/udpTracker.cpp +++ b/src/udpTracker.cpp @@ -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 . */ -#include "udpTracker.hpp" -#include "tools.h" #include // atoi #include #include #include #include +#include +#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(); + this->m_allowIANA_IPs = conf["tracker.allow_iana_ips"].as(); + this->m_isDynamic = conf["tracker.is_dynamic"].as(); - sc_tracker = settings->getClass("tracker"); + this->m_announceInterval = conf["tracker.announce_interval"].as(); + this->m_cleanupInterval = conf["tracker.cleanup_interval"].as(); + this->m_port = conf["tracker.port"].as(); + this->m_threadCount = conf["tracker.threads"].as() + 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 addrs; - sc_tracker->getIPs("bind", addrs); + std::list 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 () + 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(&timeout), sizeof(timeout)); + } + + this->m_localEndpoint.sin_family = AF_INET; + r = ::bind(sock, reinterpret_cast(&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(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); - #endif + m_threads.push_back(boost::thread(UDPTracker::_thread_start, this)); } - - return START_OK; } - int UDPTracker::sendError (UDPTracker *usi, SOCKADDR_IN *remote, uint32_t transactionID, const string &msg) + void UDPTracker::stop() + { +#ifdef linux + ::close(m_sock); +#elif defined (WIN32) + ::closesocket(m_sock); +#endif + + for (std::vector::iterator it = m_threads.begin(); it != m_threads.end(); ++it) + { + it->interrupt(); + } + + wait(); + } + + void UDPTracker::wait() + { + for (std::vector::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(remote), sizeof(*remote)); return 0; } - int UDPTracker::handleConnection (UDPTracker *usi, SOCKADDR_IN *remote, char *data) + int UDPTracker::handleConnection(UDPTracker *usi, SOCKADDR_IN *remote, char *data) { - ConnectionRequest *req; + ConnectionRequest *req = reinterpret_cast(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."); + 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(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,15 +314,15 @@ 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; } - int UDPTracker::handleScrape (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len) + int UDPTracker::handleScrape(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len) { - ScrapeRequest *sR; + ScrapeRequest *sR = reinterpret_cast(data); int v, // validation helper c, // torrent counter i, // loop counter @@ -362,18 +331,15 @@ 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) { - UDPTracker::sendError (usi, remote, sR->transaction_id, "Bad scrape request."); + UDPTracker::sendError(usi, remote, sR->transaction_id, "Bad scrape request."); 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,8 +349,8 @@ namespace UDPT // get torrent count. c = v / 20; - resp = (ScrapeResponse*)buffer; - resp->action = m_hton32 (2); + resp = reinterpret_cast(buffer); + resp->action = m_hton32(2); resp->transaction_id = sR->transaction_id; for (i = 0;i < c;i++) @@ -402,73 +368,64 @@ 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; } - *seeders = m_hton32 (tE.seeders); - *completed = m_hton32 (tE.completed); - *leechers = m_hton32 (tE.leechers); + *seeders = m_hton32(tE.seeders); + *completed = m_hton32(tE.completed); + *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(buffer), sizeof(buffer), 0, reinterpret_cast(remote), sizeof(SOCKADDR_IN)); return 0; } -static int _isIANA_IP (uint32_t ip) -{ - uint8_t x = (ip % 256); - if (x == 0 || x == 10 || x == 127 || x >= 224) - return 1; - return 0; -} - - int UDPTracker::resolveRequest (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r) + int UDPTracker::isIANAIP(uint32_t ip) { - ConnectionRequest *cR; - uint32_t action; + uint8_t x = (ip % 256); + if (x == 0 || x == 10 || x == 127 || x >= 224) + return 1; + return 0; + } - cR = (ConnectionRequest*)data; + int UDPTracker::resolveRequest(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r) + { + ConnectionRequest* cR = reinterpret_cast(data); + uint32_t action; 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); + return UDPTracker::handleConnection(usi, remote, data); else if (action == 1 && r >= 98) - return UDPTracker::handleAnnounce (usi, remote, data); + return UDPTracker::handleAnnounce(usi, remote, data); else if (action == 2) - return UDPTracker::handleScrape (usi, remote, data, r); + 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."); + UDPTracker::sendError(usi, remote, cR->transaction_id, "Tracker couldn't understand Client's request."); return -1; } 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); + 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... - r = UDPTracker::resolveRequest (usi, &remoteAddr, tmpBuff, r); - } + { + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + continue; + } - #ifdef linux - pthread_exit (NULL); - #endif - return 0; + { + boost::this_thread::disable_interruption di; + r = UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r); + } + } } -#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(); + { + boost::this_thread::disable_interruption di; + usi->m_conn->cleanup(); + } -#ifdef WIN32 - Sleep (usi->cleanup_interval * 1000); -#elif defined (linux) - sleep (usi->cleanup_interval); -#else -#error Unsupported OS. -#endif + boost::this_thread::sleep_for(boost::chrono::seconds(usi->m_cleanupInterval)); } - - return 0; } }; diff --git a/src/udpTracker.hpp b/src/udpTracker.hpp index 7a89417..5e7cf4d 100644 --- a/src/udpTracker.hpp +++ b/src/udpTracker.hpp @@ -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 +#include +#include +#include +#include +#include +#include "exceptions.h" #include "multiplatform.h" #include "db/driver_sqlite.hpp" -#include "settings.hpp" -#include -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,57 +119,57 @@ 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 wait (); + void stop(); + + /** + * Joins worker threads + */ + void wait(); /** * Destroys resources that were created by constructor * @param usi Instance to destroy. */ - virtual ~UDPTracker (); + virtual ~UDPTracker(); + + std::shared_ptr m_conn; - 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_isDynamic; + bool m_allowRemotes; + bool m_allowIANA_IPs; + std::vector 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); + static int resolveRequest(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r); - static int handleConnection (UDPTracker *usi, SOCKADDR_IN *remote, char *data); - static int handleAnnounce (UDPTracker *usi, SOCKADDR_IN *remote, char *data); - static int handleScrape (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len); + static int handleConnection(UDPTracker *usi, SOCKADDR_IN *remote, char *data); + 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); }; };