Refactored (#31)
* Build system changed to CMake * Converted tabs to spaces * Removed all usages of boost::log * Replaced boost::thread with std::thread * Update copyright year * Added a tiny bit of unit tests * Added a simple message queue * Added basic independent logging * Added CONTRIBUTING
This commit is contained in:
parent
7193f945a9
commit
f34fcdbd04
44
.github/CONTRIBUTING.md
vendored
Normal file
44
.github/CONTRIBUTING.md
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Contributing
|
||||
Thank you for looking into [UDPT](https://github.com/naim94a/udpt)!
|
||||
|
||||
This document lists various ways to contribute to UDPT. If you can, please do.
|
||||
|
||||
## Bug Reports
|
||||
Bug reports are always welcome, they help us maintain a quality product.
|
||||
|
||||
Before submitting a bug report, please first check that the issue does not already exist and that the effected version
|
||||
is the most recent one.
|
||||
|
||||
* If a similar (or same) issue already exists, please upvote, comment, elaborate on the existing issue.
|
||||
* If you found a new issue, please attach the used configuration and how to cause the bug to appear.
|
||||
* Core dumps are always welcome
|
||||
|
||||
Bugs should be reported at [UDPT's issue tracker](https://github.com/naim94a/udpt) on GitHub.
|
||||
|
||||
## Suggesting new features
|
||||
New features are welcome, it doesn't mean they will enter immediately.
|
||||
|
||||
Suggestions should be filed as issues along with bug reports, just add the "enhancement" label to the created issue.
|
||||
|
||||
## Donations
|
||||
Please show us your appreciation by donating BitCoin at bitcoin:1KMeZvcgnmWdHitu51yEFWBNcSTXL1eBk3.
|
||||
|
||||
![bitcoin:1KMeZvcgnmWdHitu51yEFWBNcSTXL1eBk3](bitcoin-qr.png)
|
||||
|
||||
## Pull requests
|
||||
Before submitting a pull request, please check that the changes don't effect other platforms or have any unwanted
|
||||
side-effects.
|
||||
|
||||
Pull Requests should address open issue(s), where the project owner and contributors can discuss how the issue should be
|
||||
addressed.
|
||||
|
||||
Pull requests that add new features should be first mentioned in issues in order to verify that the project owner will
|
||||
allow such changes to the project.
|
||||
|
||||
Code in pull requests should meet the following requirements:
|
||||
|
||||
* Class names should be CamelCase, and the first letter should be capital.
|
||||
* Functions should be camelCase, and the first letter should be lower-case.
|
||||
* Class members should be prefixed with `m_`, for example: `bool m_isRunning`
|
||||
* All variables, classes, functions and class members should have an indicative name.
|
||||
* Adding external libraries is allowed, but frowned upon
|
BIN
.github/bitcoin-qr.png
vendored
Normal file
BIN
.github/bitcoin-qr.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -1,15 +1,24 @@
|
|||
project(udpt)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
enable_testing()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
add_definitions(-DBOOST_LOG_DYN_LINK)
|
||||
|
||||
file(GLOB src_files "src/*.c"
|
||||
"src/*.cpp"
|
||||
"src/db/*.cpp"
|
||||
"src/http/*.cpp")
|
||||
|
||||
LIST(APPEND LIBS "pthread" "sqlite3" "boost_program_options" "boost_system")
|
||||
|
||||
|
||||
add_executable(udpt ${src_files})
|
||||
target_link_libraries(udpt pthread sqlite3 boost_log boost_program_options boost_thread boost_system)
|
||||
target_link_libraries(udpt ${LIBS})
|
||||
|
||||
add_executable(udpt_tests tests/main.cpp ${src_files})
|
||||
target_compile_definitions(udpt_tests PRIVATE TEST=1)
|
||||
|
||||
target_link_libraries(udpt_tests gtest ${LIBS})
|
||||
|
||||
add_test(NAME udpt_tests COMMAND udpt_tests)
|
64
src/MessageQueue.hpp
Normal file
64
src/MessageQueue.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright © 2012-2017 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 <queue>
|
||||
#include <mutex>
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
namespace Utils {
|
||||
|
||||
template<class T>
|
||||
class MessageQueue {
|
||||
public:
|
||||
MessageQueue() {}
|
||||
|
||||
virtual ~MessageQueue() {}
|
||||
|
||||
bool IsEmpty() const {
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
T Pop() {
|
||||
m_queueMutex.lock();
|
||||
T val = m_queue.front();
|
||||
m_queue.pop();
|
||||
m_queueMutex.unlock();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void Push(T obj) {
|
||||
m_queueMutex.lock();
|
||||
m_queue.push(obj);
|
||||
m_queueMutex.unlock();
|
||||
}
|
||||
|
||||
size_t Count() const {
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<T> m_queue;
|
||||
std::mutex m_queueMutex;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -21,8 +21,6 @@
|
|||
#define DATABASE_HPP_
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include <cassert>
|
||||
#include <cstring> // memcpy
|
||||
#include "../multiplatform.h"
|
||||
#include "../logging.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -66,7 +67,7 @@ namespace UDPT
|
|||
return data;
|
||||
}
|
||||
|
||||
SQLite3Driver::SQLite3Driver(const boost::program_options::variables_map& conf, bool isDyn) : DatabaseDriver(conf, isDyn), m_logger(boost::log::keywords::channel="SQLite3")
|
||||
SQLite3Driver::SQLite3Driver(const boost::program_options::variables_map& conf, bool isDyn) : DatabaseDriver(conf, isDyn)
|
||||
{
|
||||
int r;
|
||||
bool doSetup;
|
||||
|
@ -86,6 +87,7 @@ namespace UDPT
|
|||
r = sqlite3_open(filename.c_str(), &this->db);
|
||||
if (r != SQLITE_OK)
|
||||
{
|
||||
LOG_FATAL("db-sqlite", "Failed to connect DB. sqlite returned " << r);
|
||||
sqlite3_close(this->db);
|
||||
throw DatabaseException (DatabaseException::E_CONNECTION_FAILURE);
|
||||
}
|
||||
|
@ -97,6 +99,7 @@ namespace UDPT
|
|||
void SQLite3Driver::doSetup()
|
||||
{
|
||||
char *eMsg = NULL;
|
||||
LOG_INFO("db-sqlite", "Setting up database...");
|
||||
// for quicker stats.
|
||||
sqlite3_exec(this->db, "CREATE TABLE stats ("
|
||||
"info_hash blob(20) UNIQUE,"
|
||||
|
@ -177,8 +180,6 @@ namespace UDPT
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Retrieved " << i << " peers";
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
*max_count = i;
|
||||
|
@ -259,12 +260,10 @@ namespace UDPT
|
|||
|
||||
if (SQLITE_OK == r)
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Added torrent";
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::error) << "Failed to add torrent: SQLite3 error code = " << r;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -286,17 +285,26 @@ namespace UDPT
|
|||
|
||||
void SQLite3Driver::cleanup()
|
||||
{
|
||||
LOG_INFO("db-sqlite", "Cleaning up...");
|
||||
int exp = time (NULL) - 7200; // 2 hours, expired.
|
||||
int r = 0;
|
||||
|
||||
// drop all peers with no activity for 2 hours.
|
||||
sqlite3_stmt *getTables;
|
||||
// torrent table names: t<hex-of-sha-1>
|
||||
sqlite3_prepare(this->db, "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 't________________________________________'", -1, &getTables, NULL);
|
||||
r = sqlite3_prepare(this->db, "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 't________________________________________'", -1, &getTables, NULL);
|
||||
if (r != SQLITE_OK) {
|
||||
LOG_ERR("db-sqlite", "Failed fetch tables from DB for cleanup.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buff [20];
|
||||
sqlite3_stmt *updateStats;
|
||||
assert (sqlite3_prepare(this->db, "REPLACE INTO stats (info_hash,seeders,leechers,last_mod) VALUES (?,?,?,?)", -1, &updateStats, NULL) == SQLITE_OK);
|
||||
|
||||
r = sqlite3_prepare(this->db, "REPLACE INTO stats (info_hash,seeders,leechers,last_mod) VALUES (?,?,?,?)", -1, &updateStats, NULL);
|
||||
if (r != SQLITE_OK) {
|
||||
LOG_ERR("db-sqlite", "Failed to prepare update stats query.");
|
||||
return;
|
||||
}
|
||||
|
||||
while (sqlite3_step(getTables) == SQLITE_ROW)
|
||||
{
|
||||
|
@ -304,18 +312,23 @@ namespace UDPT
|
|||
stringstream sStr;
|
||||
sStr << "DELETE FROM " << tblN << " WHERE last_seen<" << exp;
|
||||
|
||||
assert (sqlite3_exec(this->db, sStr.str().c_str(), NULL, NULL, NULL) == SQLITE_OK);
|
||||
r = sqlite3_exec(this->db, sStr.str().c_str(), NULL, NULL, NULL);
|
||||
if (r != SQLITE_OK) {
|
||||
LOG_ERR("db-sqlite", "Failed to execute cleanup for table '" << tblN << "'.");
|
||||
continue;
|
||||
}
|
||||
|
||||
sStr.str (string());
|
||||
sStr << "SELECT left,COUNT(*) FROM " << tblN << " GROUP BY left==0";
|
||||
|
||||
sqlite3_stmt *collectStats;
|
||||
|
||||
sqlite3_prepare(this->db, sStr.str().c_str(), sStr.str().length(), &collectStats, NULL);
|
||||
r = sqlite3_prepare(this->db, sStr.str().c_str(), sStr.str().length(), &collectStats, NULL);
|
||||
|
||||
if (sqlite3_errcode(this->db) != SQLITE_OK)
|
||||
if (r != SQLITE_OK)
|
||||
{
|
||||
// TODO: Log this error
|
||||
LOG_ERR("db-sqlite", "Failed while trying to prepare stats query for '" << tblN << "', sqlite returned " << r);
|
||||
continue;
|
||||
}
|
||||
|
||||
int seeders = 0, leechers = 0;
|
||||
|
@ -340,8 +353,7 @@ namespace UDPT
|
|||
sqlite3_finalize(getTables);
|
||||
}
|
||||
|
||||
bool SQLite3Driver::removeTorrent(uint8_t info_hash[20])
|
||||
{
|
||||
bool SQLite3Driver::removeTorrent(uint8_t info_hash[20]) {
|
||||
// if non-dynamic, remove from table
|
||||
sqlite3_stmt *stmt;
|
||||
sqlite3_prepare(this->db, "DELETE FROM torrents WHERE info_hash=?", -1, &stmt, NULL);
|
||||
|
@ -368,13 +380,10 @@ namespace UDPT
|
|||
|
||||
sqlite3_exec(this->db, str.c_str(), NULL, NULL, NULL);
|
||||
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Torrent removed.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SQLite3Driver::removePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port)
|
||||
{
|
||||
bool SQLite3Driver::removePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port) {
|
||||
string sql;
|
||||
char xHash [50];
|
||||
sqlite3_stmt *stmt;
|
||||
|
@ -398,8 +407,7 @@ namespace UDPT
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint64_t _genCiD (uint32_t ip, uint16_t port)
|
||||
{
|
||||
static uint64_t _genCiD (uint32_t ip, uint16_t port) {
|
||||
uint64_t x;
|
||||
x = (time(NULL) / 3600) * port; // x will probably overload.
|
||||
x = (ip ^ port);
|
||||
|
@ -408,23 +416,19 @@ namespace UDPT
|
|||
return x;
|
||||
}
|
||||
|
||||
bool SQLite3Driver::genConnectionId (uint64_t *connectionId, uint32_t ip, uint16_t port)
|
||||
{
|
||||
bool SQLite3Driver::genConnectionId (uint64_t *connectionId, uint32_t ip, uint16_t port) {
|
||||
*connectionId = _genCiD(ip, port);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SQLite3Driver::verifyConnectionId(uint64_t cId, uint32_t ip, uint16_t port)
|
||||
{
|
||||
bool SQLite3Driver::verifyConnectionId(uint64_t cId, uint32_t ip, uint16_t port) {
|
||||
if (cId == _genCiD(ip, port))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
SQLite3Driver::~SQLite3Driver()
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Closing SQLite";
|
||||
SQLite3Driver::~SQLite3Driver() {
|
||||
sqlite3_close(this->db);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -46,7 +46,6 @@ namespace UDPT
|
|||
virtual ~SQLite3Driver();
|
||||
private:
|
||||
sqlite3 *db;
|
||||
boost::log::sources::severity_channel_logger_mt<> m_logger;
|
||||
|
||||
void doSetup();
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
* Copyright © 2013-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
* Copyright © 2013-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
* Copyright © 2013-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2013-2016 Naim A.
|
||||
* Copyright © 2013-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
140
src/logging.cpp
Normal file
140
src/logging.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright © 2012-2017 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 "logging.hpp"
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace UDPT {
|
||||
namespace Logging {
|
||||
|
||||
Logger::Logger() : m_cleaningUp(false), m_workerThread(Logger::worker, this), m_minLogLevel(Severity::FATAL) {
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
try {
|
||||
// prevent new log messages from entering queue.
|
||||
m_cleaningUp = true;
|
||||
|
||||
// tell thread to exit
|
||||
m_runningCondition.notify_one();
|
||||
|
||||
// wait for worker to terminate
|
||||
m_workerThread.join();
|
||||
// flush any remaining logs
|
||||
flush();
|
||||
|
||||
// flush iostreams
|
||||
for (std::vector<std::pair<std::ostream*, Severity>>::const_iterator it = m_outputStreams.begin(); it != m_outputStreams.end(); ++it) {
|
||||
it->first->flush();
|
||||
}
|
||||
} catch (...) {
|
||||
// can't do much here... this is a logging class...
|
||||
}
|
||||
}
|
||||
|
||||
Logger& Logger::getLogger() {
|
||||
static Logger instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Logger::log(Severity severity, const std::string& channel, const std::string& message) {
|
||||
if (severity < m_minLogLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_queue.Push(LogEntry{
|
||||
.when=std::chrono::system_clock::now(),
|
||||
.severity=severity,
|
||||
.channel=channel,
|
||||
.message=message
|
||||
});
|
||||
}
|
||||
|
||||
void Logger::addStream(std::ostream *stream, Severity severity) {
|
||||
m_minLogLevel = m_minLogLevel > severity ? severity : m_minLogLevel;
|
||||
m_outputStreams.push_back(std::pair<std::ostream*, Severity>(stream, severity));
|
||||
}
|
||||
|
||||
void Logger::flush() {
|
||||
while (!m_queue.IsEmpty()) {
|
||||
LogEntry entry = m_queue.Pop();
|
||||
std::stringstream sstream;
|
||||
|
||||
//TODO: Write the log time in a more elegant manner.
|
||||
time_t timestamp = std::chrono::system_clock::to_time_t(entry.when);
|
||||
char* time_buffer = ctime(×tamp);
|
||||
time_buffer[strlen(time_buffer) - 1] = '\0';
|
||||
sstream << time_buffer << "\t";
|
||||
|
||||
switch (entry.severity) {
|
||||
case Severity::DEBUG:
|
||||
sstream << "DEBUG";
|
||||
break;
|
||||
case Severity::INFO:
|
||||
sstream << "INFO ";
|
||||
break;
|
||||
case Severity::WARNING:
|
||||
sstream << "WARN ";
|
||||
break;
|
||||
case Severity::ERROR:
|
||||
sstream << "ERROR";
|
||||
break;
|
||||
case Severity::FATAL:
|
||||
sstream << "FATAL";
|
||||
break;
|
||||
}
|
||||
|
||||
sstream << " [" << entry.channel << "]\t" << entry.message;
|
||||
|
||||
const std::string& result_log = sstream.str();
|
||||
for (std::vector<std::pair<std::ostream*, Severity>>::const_iterator it = m_outputStreams.begin(); it != m_outputStreams.end(); ++it) {
|
||||
|
||||
if (entry.severity < it->second) {
|
||||
// message severity isn't high enough for this logger.
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ostream& current_stream = *(it->first);
|
||||
|
||||
// catch an exception in case we get a broken pipe or something...
|
||||
try {
|
||||
current_stream << result_log << std::endl;
|
||||
} catch (...) {
|
||||
// do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::worker(Logger *me) {
|
||||
std::unique_lock<std::mutex> lk (me->m_runningMutex);
|
||||
|
||||
while (true) {
|
||||
me->flush();
|
||||
|
||||
if (std::cv_status::no_timeout == me->m_runningCondition.wait_for(lk, std::chrono::seconds(5))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
src/logging.hpp
Normal file
83
src/logging.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright © 2012-2017 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 <string>
|
||||
#include <ostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include "MessageQueue.hpp"
|
||||
|
||||
#define LOG(severity, channel, message) \
|
||||
{\
|
||||
std::stringstream __sstream; \
|
||||
__sstream << message; \
|
||||
UDPT::Logging::Logger::getLogger().log(severity, channel, __sstream.str()); \
|
||||
}
|
||||
#define LOG_INFO(channel, message) LOG(UDPT::Logging::Severity::INFO, channel, message)
|
||||
#define LOG_DEBUG(channel, message) LOG(UDPT::Logging::Severity::DEBUG, channel, message)
|
||||
#define LOG_WARN(channel, message) LOG(UDPT::Logging::Severity::WARNING, channel, message)
|
||||
#define LOG_ERR(channel, message) LOG(UDPT::Logging::Severity::ERROR, channel, message)
|
||||
#define LOG_FATAL(channel, message) LOG(UDPT::Logging::Severity::FATAL, channel, message)
|
||||
|
||||
namespace UDPT {
|
||||
namespace Logging {
|
||||
|
||||
enum Severity {
|
||||
UNSET = 0,
|
||||
DEBUG = 10,
|
||||
INFO = 20,
|
||||
WARNING = 30,
|
||||
ERROR = 40,
|
||||
FATAL = 50
|
||||
};
|
||||
|
||||
struct LogEntry {
|
||||
const std::chrono::time_point<std::chrono::system_clock> when;
|
||||
Severity severity;
|
||||
const std::string channel;
|
||||
const std::string message;
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
static Logger& getLogger();
|
||||
|
||||
void log(Severity severity, const std::string& channel, const std::string& message);
|
||||
|
||||
void addStream(std::ostream *, Severity minSeverity=INFO);
|
||||
|
||||
private:
|
||||
|
||||
Logger();
|
||||
virtual ~Logger();
|
||||
static void worker(Logger*);
|
||||
void flush();
|
||||
|
||||
std::vector<std::pair<std::ostream*, UDPT::Logging::Severity>> m_outputStreams;
|
||||
UDPT::Utils::MessageQueue<struct LogEntry> m_queue;
|
||||
std::thread m_workerThread;
|
||||
std::atomic_bool m_cleaningUp;
|
||||
std::mutex m_runningMutex;
|
||||
std::condition_variable m_runningCondition;
|
||||
Severity m_minLogLevel;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
26
src/main.cpp
26
src/main.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -25,8 +25,6 @@
|
|||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
|
||||
#include "multiplatform.h"
|
||||
#include "udpTracker.hpp"
|
||||
|
@ -34,16 +32,20 @@
|
|||
#include "http/webapp.hpp"
|
||||
#include "tracker.hpp"
|
||||
#include "service.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
static void _signal_handler(int sig)
|
||||
{
|
||||
switch (sig)
|
||||
extern "C" void _signal_handler(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGINT: {
|
||||
LOG_INFO("core", "Received signal " << sig << ", requesting to stop tracker");
|
||||
UDPT::Tracker::getInstance().stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
static void daemonize(const boost::program_options::variables_map& conf)
|
||||
|
@ -74,7 +76,11 @@ void _close_wsa()
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
int real_main(int argc, char *argv[])
|
||||
#else
|
||||
int main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
@ -145,15 +151,13 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
boost::log::sources::severity_channel_logger_mt<> logger(boost::log::keywords::channel = "main");
|
||||
Tracker::setupLogging(var_map, logger);
|
||||
|
||||
#ifdef linux
|
||||
if (!var_map.count("interactive"))
|
||||
{
|
||||
daemonize(var_map);
|
||||
}
|
||||
::signal(SIGTERM, _signal_handler);
|
||||
::signal(SIGINT, _signal_handler);
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
UDPT::Service svc(var_map);
|
||||
|
@ -220,9 +224,11 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
catch (const UDPT::UDPTException& ex)
|
||||
{
|
||||
BOOST_LOG_SEV(logger, boost::log::trivial::fatal) << "UDPT exception: (" << ex.getErrorCode() << "): " << ex.what();
|
||||
std::cerr << "UDPT exception: (" << ex.getErrorCode() << "): " << ex.what();
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INFO("core", "UDPT terminated.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -16,52 +16,60 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "tracker.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
Tracker::Tracker() : m_logger(boost::log::keywords::channel = "TRACKER")
|
||||
Tracker::Tracker() : m_logStream(nullptr)
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Initialized Tracker";
|
||||
}
|
||||
|
||||
Tracker::~Tracker()
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Destroying Tracker...";
|
||||
try {
|
||||
if (nullptr != m_logStream) {
|
||||
m_logStream->flush();
|
||||
delete m_logStream;
|
||||
m_logStream = nullptr;
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Tracker::stop()
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Requesting Tracker to terminate.";
|
||||
LOG_INFO("tracker", "Requesting components to terminate...");
|
||||
m_udpTracker->stop();
|
||||
wait();
|
||||
|
||||
// cause other components to destruct.
|
||||
m_apiSrv = nullptr;
|
||||
m_webApp = nullptr;
|
||||
m_udpTracker = nullptr;
|
||||
}
|
||||
|
||||
void Tracker::wait()
|
||||
{
|
||||
m_udpTracker->wait();
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Tracker terminated.";
|
||||
}
|
||||
|
||||
void Tracker::start(const boost::program_options::variables_map& conf)
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Starting Tracker...";
|
||||
setupLogging(conf);
|
||||
LOG_INFO("core", "Initializing...");
|
||||
|
||||
m_udpTracker = std::shared_ptr<UDPTracker>(new UDPTracker(conf));
|
||||
|
||||
if (conf["apiserver.enable"].as<bool>())
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Initializing and deploying WebAPI...";
|
||||
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();
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Tracker started.";
|
||||
}
|
||||
|
||||
Tracker& Tracker::getInstance()
|
||||
|
@ -91,7 +99,7 @@ namespace UDPT
|
|||
("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("/var/log/udpt.log"), "file to write logs to")
|
||||
("logging.level", boost::program_options::value<std::string>()->default_value("warning"), "log level (fatal/error/warning/info/debug/trace)")
|
||||
("logging.level", boost::program_options::value<std::string>()->default_value("warning"), "log level (fatal/error/warning/info/debug)")
|
||||
|
||||
#ifdef linux
|
||||
("daemon.chdir", boost::program_options::value<std::string>()->default_value("/"), "home directory for daemon")
|
||||
|
@ -104,42 +112,40 @@ namespace UDPT
|
|||
return configOptions;
|
||||
}
|
||||
|
||||
void Tracker::setupLogging(const boost::program_options::variables_map& config, boost::log::sources::severity_channel_logger_mt<>& logger)
|
||||
{
|
||||
boost::log::add_common_attributes();
|
||||
boost::shared_ptr<boost::log::sinks::text_file_backend> logBackend = boost::make_shared<boost::log::sinks::text_file_backend>(
|
||||
boost::log::keywords::file_name = config["logging.filename"].as<std::string>(),
|
||||
boost::log::keywords::auto_flush = true,
|
||||
boost::log::keywords::open_mode = std::ios::out | std::ios::app
|
||||
);
|
||||
typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_file_backend> udptSink_t;
|
||||
boost::shared_ptr<udptSink_t> async_sink(new udptSink_t(logBackend));
|
||||
async_sink->set_formatter(
|
||||
boost::log::expressions::stream
|
||||
<< boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S") << " "
|
||||
<< boost::log::expressions::attr<int>("Severity")
|
||||
<< " [" << boost::log::expressions::attr<std::string>("Channel") << "] \t"
|
||||
<< boost::log::expressions::smessage
|
||||
);
|
||||
auto loggingCore = boost::log::core::get();
|
||||
loggingCore->add_sink(async_sink);
|
||||
void Tracker::setupLogging(const boost::program_options::variables_map& va_map) {
|
||||
Logging::Logger& logger = Logging::Logger::getLogger();
|
||||
|
||||
std::string severity = config["logging.level"].as<std::string>();
|
||||
std::transform(severity.begin(), severity.end(), severity.begin(), ::tolower);
|
||||
int severityVal = boost::log::trivial::warning;
|
||||
if ("fatal" == severity) severityVal = boost::log::trivial::fatal;
|
||||
else if ("error" == severity) severityVal = boost::log::trivial::error;
|
||||
else if ("warning" == severity) severityVal = boost::log::trivial::warning;
|
||||
else if ("info" == severity) severityVal = boost::log::trivial::info;
|
||||
else if ("debug" == severity) severityVal = boost::log::trivial::debug;
|
||||
else if ("trace" == severity) severityVal = boost::log::trivial::trace;
|
||||
else
|
||||
{
|
||||
BOOST_LOG_SEV(logger, boost::log::trivial::warning) << "Unknown debug level \"" << severity << "\" defaulting to warning";
|
||||
logger.addStream(&std::cerr, Logging::Severity::FATAL);
|
||||
|
||||
Logging::Severity severity;
|
||||
std::string severity_text = va_map["logging.level"].as<std::string>();
|
||||
std::transform(severity_text.begin(), severity_text.end(), severity_text.begin(), ::tolower);
|
||||
|
||||
if (severity_text == "fatal") {
|
||||
severity = Logging::Severity::FATAL;
|
||||
} else if (severity_text == "error") {
|
||||
severity = Logging::Severity::ERROR;
|
||||
} else if (severity_text == "warning") {
|
||||
severity = Logging::Severity::WARNING;
|
||||
} else if (severity_text == "info") {
|
||||
severity = Logging::Severity::INFO;
|
||||
} else if (severity_text == "debug") {
|
||||
severity = Logging::Severity::DEBUG;
|
||||
} else {
|
||||
severity = Logging::Severity::UNSET;
|
||||
}
|
||||
|
||||
loggingCore->set_filter(
|
||||
boost::log::trivial::severity >= severityVal
|
||||
);
|
||||
const std::string& logFileName = va_map["logging.filename"].as<std::string>();
|
||||
Logging::Severity real_severity = (severity == Logging::Severity::UNSET ? Logging::Severity::INFO : severity);
|
||||
if (logFileName.length() == 0 || logFileName == "--") {
|
||||
logger.addStream(&std::cerr, real_severity);
|
||||
} else {
|
||||
m_logStream = new ofstream(logFileName, std::ios::app | std::ios::out);
|
||||
logger.addStream(m_logStream, real_severity);
|
||||
}
|
||||
|
||||
if (severity != real_severity) {
|
||||
LOG_WARN("core", "'" << severity_text << "' is invalid, log level set to " << real_severity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -21,16 +21,7 @@
|
|||
#include <memory>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sinks/text_file_backend.hpp>
|
||||
#include <boost/log/sinks/async_frontend.hpp>
|
||||
#include <boost/log/keywords/format.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/support/date_time.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
|
||||
#include "multiplatform.h"
|
||||
#include "udpTracker.hpp"
|
||||
|
@ -55,14 +46,14 @@ namespace UDPT
|
|||
|
||||
static boost::program_options::options_description getConfigOptions();
|
||||
|
||||
static void setupLogging(const boost::program_options::variables_map& config, boost::log::sources::severity_channel_logger_mt<>& logger);
|
||||
|
||||
private:
|
||||
std::shared_ptr<UDPT::UDPTracker> m_udpTracker;
|
||||
std::shared_ptr<UDPT::Server::HTTPServer> m_apiSrv;
|
||||
std::shared_ptr<UDPT::Server::WebApp> m_webApp;
|
||||
boost::log::sources::severity_channel_logger_mt<> m_logger;
|
||||
|
||||
Tracker();
|
||||
|
||||
void setupLogging(const boost::program_options::variables_map& va_map);
|
||||
std::ostream *m_logStream;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "udpTracker.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
|
||||
using namespace UDPT::Data;
|
||||
|
@ -26,8 +27,7 @@ using namespace UDPT::Data;
|
|||
|
||||
namespace UDPT
|
||||
{
|
||||
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf), m_logger(boost::log::keywords::channel = "UDPTracker")
|
||||
{
|
||||
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf) {
|
||||
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>();
|
||||
|
@ -37,28 +37,17 @@ namespace UDPT
|
|||
this->m_port = conf["tracker.port"].as<unsigned short>();
|
||||
this->m_threadCount = conf["tracker.threads"].as<unsigned>() + 1;
|
||||
|
||||
std::list<SOCKADDR_IN> addrs;
|
||||
|
||||
if (addrs.empty())
|
||||
{
|
||||
SOCKADDR_IN sa;
|
||||
sa.sin_port = m_hton16(m_port);
|
||||
sa.sin_addr.s_addr = 0L;
|
||||
addrs.push_back(sa);
|
||||
}
|
||||
|
||||
this->m_localEndpoint = addrs.front();
|
||||
this->m_localEndpoint.sin_family = AF_INET;
|
||||
this->m_localEndpoint.sin_port = m_hton16(m_port);
|
||||
this->m_localEndpoint.sin_addr.s_addr = 0L;
|
||||
|
||||
this->m_conn = std::shared_ptr<DatabaseDriver>(new Data::SQLite3Driver(m_conf, this->m_isDynamic));
|
||||
}
|
||||
|
||||
UDPTracker::~UDPTracker()
|
||||
{
|
||||
stop();
|
||||
UDPTracker::~UDPTracker() {
|
||||
}
|
||||
|
||||
void UDPTracker::start()
|
||||
{
|
||||
void UDPTracker::start() {
|
||||
SOCKET sock;
|
||||
int r, // saves results
|
||||
i, // loop index
|
||||
|
@ -68,6 +57,7 @@ namespace UDPT
|
|||
sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == INVALID_SOCKET)
|
||||
{
|
||||
LOG_FATAL("udp-tracker", "Failed to create socket. error=" << errno);
|
||||
throw UDPT::UDPTException("Failed to create socket");
|
||||
}
|
||||
|
||||
|
@ -92,6 +82,8 @@ namespace UDPT
|
|||
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
LOG_FATAL("udp-tracker", "Failed to bind socket. error=" << errno);
|
||||
|
||||
#ifdef WIN32
|
||||
::closesocket(sock);
|
||||
#elif defined (linux)
|
||||
|
@ -100,52 +92,52 @@ namespace UDPT
|
|||
throw UDPT::UDPTException("Failed to bind socket.");
|
||||
}
|
||||
|
||||
{
|
||||
char buff[INET_ADDRSTRLEN];
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "UDP tracker bound on " << ::inet_ntop(AF_INET, reinterpret_cast<LPVOID>(&m_localEndpoint.sin_addr), buff, sizeof(buff)) << ":" << htons(m_localEndpoint.sin_port);
|
||||
}
|
||||
|
||||
this->m_sock = sock;
|
||||
|
||||
LOG_INFO("udp-tracker", "Tracker bound to " << inet_ntoa(this->m_localEndpoint.sin_addr));
|
||||
|
||||
// create maintainer thread.
|
||||
m_threads.push_back(std::thread(UDPTracker::_maintainance_start, this));
|
||||
LOG_INFO("udp-tracker", "Started maintenance thread @" << m_threads.back().get_id());
|
||||
|
||||
m_threads.push_back(boost::thread(UDPTracker::_maintainance_start, this));
|
||||
|
||||
m_shouldRun = true;
|
||||
for (i = 1;i < this->m_threadCount; i++)
|
||||
{
|
||||
m_threads.push_back(boost::thread(UDPTracker::_thread_start, this));
|
||||
m_threads.push_back(std::thread(UDPTracker::_thread_start, this));
|
||||
LOG_INFO("udp-tracker", "Started worker thread @" << m_threads.back().get_id());
|
||||
}
|
||||
}
|
||||
|
||||
void UDPTracker::stop()
|
||||
void UDPTracker::stop() {
|
||||
// tell workers to stop running...
|
||||
m_shouldRun = false;
|
||||
|
||||
// stop maintenance thread's sleep...
|
||||
m_maintenanceCondition.notify_one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief blocks until all threads die.
|
||||
* @note This method should be called only once, preferably by the main thread.
|
||||
* **/
|
||||
void UDPTracker::wait() {
|
||||
LOG_INFO("udp-tracker", "Waiting for threads to terminate...");
|
||||
|
||||
for (std::vector<std::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
it->join();
|
||||
}
|
||||
|
||||
LOG_INFO("udp-tracker", "UDP Tracker terminated");
|
||||
|
||||
#ifdef linux
|
||||
::close(m_sock);
|
||||
#elif defined (WIN32)
|
||||
::closesocket(m_sock);
|
||||
#endif
|
||||
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::warning) << "Interrupting workers...";
|
||||
for (std::vector<boost::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
it->interrupt();
|
||||
}
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
void UDPTracker::wait()
|
||||
{
|
||||
BOOST_LOG_SEV(m_logger, boost::log::trivial::warning) << "Waiting for threads to terminate...";
|
||||
|
||||
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)
|
||||
{
|
||||
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.
|
||||
i; // copy loop
|
||||
|
@ -169,11 +161,12 @@ namespace UDPT
|
|||
|
||||
::sendto(usi->m_sock, buff, msg_sz, 0, reinterpret_cast<SOCKADDR*>(remote), sizeof(*remote));
|
||||
|
||||
LOG_DEBUG("udp-tracker", "Error sent to " << inet_ntoa(remote->sin_addr) << ", '" << msg << "' (len=" << msg_sz << ")");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::handleConnection(UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
int UDPTracker::handleConnection(UDPTracker *usi, SOCKADDR_IN *remote, char *data) {
|
||||
ConnectionRequest *req = reinterpret_cast<ConnectionRequest*>(data);
|
||||
ConnectionResponse resp;
|
||||
|
||||
|
@ -189,17 +182,10 @@ namespace UDPT
|
|||
|
||||
::sendto(usi->m_sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
{
|
||||
char buffer[INET_ADDRSTRLEN];
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::debug) << "Connection Request from " << ::inet_ntop(AF_INET, &remote->sin_addr, buffer, sizeof(buffer)) << "; cId=" << resp.connection_id << "; tId=" << resp.transaction_id;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::handleAnnounce(UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
int UDPTracker::handleAnnounce(UDPTracker *usi, SOCKADDR_IN *remote, char *data) {
|
||||
AnnounceRequest *req;
|
||||
AnnounceResponse *resp;
|
||||
int q, // peer counts
|
||||
|
@ -303,6 +289,7 @@ namespace UDPT
|
|||
}
|
||||
}
|
||||
::sendto(usi->m_sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
LOG_DEBUG("udp-tracker", "Announce request from " << inet_ntoa(remote->sin_addr) << " (event=" << event << "), Sent " << q << " peers");
|
||||
|
||||
// update DB.
|
||||
uint32_t ip;
|
||||
|
@ -316,8 +303,7 @@ namespace UDPT
|
|||
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 = reinterpret_cast<ScrapeRequest*>(data);
|
||||
int v, // validation helper
|
||||
c, // torrent counter
|
||||
|
@ -339,6 +325,7 @@ namespace UDPT
|
|||
m_hton32(remote->sin_addr.s_addr),
|
||||
m_hton16(remote->sin_port)))
|
||||
{
|
||||
LOG_DEBUG("udp-tracker", "Bad connection id from " << inet_ntoa(remote->sin_addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -376,20 +363,19 @@ namespace UDPT
|
|||
}
|
||||
|
||||
::sendto(usi->m_sock, reinterpret_cast<const char*>(buffer), sizeof(buffer), 0, reinterpret_cast<SOCKADDR*>(remote), sizeof(SOCKADDR_IN));
|
||||
LOG_DEBUG("udp-tracker", "Scrape request from " << inet_ntoa(remote->sin_addr) << ", Sent " << c << " torrents");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::isIANAIP(uint32_t ip)
|
||||
{
|
||||
int UDPTracker::isIANAIP(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::resolveRequest(UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r) {
|
||||
ConnectionRequest* cR = reinterpret_cast<ConnectionRequest*>(data);
|
||||
uint32_t action;
|
||||
|
||||
|
@ -399,18 +385,11 @@ namespace UDPT
|
|||
{
|
||||
if (isIANAIP(remote->sin_addr.s_addr))
|
||||
{
|
||||
char buffer[INET_ADDRSTRLEN];
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::warning) << "Client ignored (IANA IP): " << ::inet_ntop(AF_INET, &remote->sin_addr, buffer, sizeof(buffer));
|
||||
LOG_DEBUG("udp-tracker", "Request from IANA reserved IP rejected (" << inet_ntoa(remote->sin_addr) << ")");
|
||||
return 0; // Access Denied: IANA reserved IP.
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
char buffer[INET_ADDRSTRLEN];
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::debug) << "Client request from " << ::inet_ntop(AF_INET, &remote->sin_addr, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
if (action == 0 && r >= 16)
|
||||
return UDPTracker::handleConnection(usi, remote, data);
|
||||
else if (action == 1 && r >= 98)
|
||||
|
@ -422,13 +401,9 @@ namespace UDPT
|
|||
UDPTracker::sendError(usi, remote, cR->transaction_id, "Tracker couldn't understand Client's request.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UDPTracker::_thread_start(UDPTracker *usi)
|
||||
{
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::info) << "Worker thread started with PID=" << boost::this_thread::get_id() << ".";
|
||||
void UDPTracker::_thread_start(UDPTracker *usi) {
|
||||
SOCKADDR_IN remoteAddr;
|
||||
char tmpBuff[UDP_BUFFER_SIZE];
|
||||
|
||||
|
@ -440,38 +415,36 @@ namespace UDPT
|
|||
|
||||
addrSz = sizeof(SOCKADDR_IN);
|
||||
|
||||
|
||||
while (true)
|
||||
while (usi->m_shouldRun)
|
||||
{
|
||||
// peek into the first 12 bytes of data; determine if connection request or announce request.
|
||||
int r = ::recvfrom(usi->m_sock, (char*)tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
|
||||
if (r <= 0)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
std::this_thread::yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
boost::this_thread::disable_interruption di;
|
||||
|
||||
UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("udp-tracker", "worker " << std::this_thread::get_id() << " exited.");
|
||||
}
|
||||
|
||||
void UDPTracker::_maintainance_start(UDPTracker* usi)
|
||||
{
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::info) << "Maintenance thread started with PID=" << boost::this_thread::get_id() << ".";
|
||||
void UDPTracker::_maintainance_start(UDPTracker* usi) {
|
||||
std::unique_lock<std::mutex> lk (usi->m_maintenanceMutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
boost::this_thread::disable_interruption di;
|
||||
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::info) << "Running cleanup...";
|
||||
if (std::cv_status::no_timeout == usi->m_maintenanceCondition.wait_for(lk, std::chrono::seconds(usi->m_cleanupInterval))) {
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INFO("udp-tracker", "Maintenance running...");
|
||||
usi->m_conn->cleanup();
|
||||
}
|
||||
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(usi->m_cleanupInterval));
|
||||
lk.unlock();
|
||||
LOG_INFO("udp-tracker", "Maintenance thread " << std::this_thread::get_id() << " existed.");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012-2016 Naim A.
|
||||
* Copyright © 2012-2017 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
|
@ -29,10 +29,10 @@
|
|||
#include <list>
|
||||
#include <ctime>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <thread>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "tools.h"
|
||||
#include "exceptions.h"
|
||||
|
@ -160,10 +160,13 @@ namespace UDPT
|
|||
bool m_isDynamic;
|
||||
bool m_allowRemotes;
|
||||
bool m_allowIANA_IPs;
|
||||
std::vector<boost::thread> m_threads;
|
||||
std::vector<std::thread> m_threads;
|
||||
uint32_t m_announceInterval;
|
||||
uint32_t m_cleanupInterval;
|
||||
boost::log::sources::severity_channel_logger_mt<> m_logger;
|
||||
std::atomic_bool m_shouldRun;
|
||||
|
||||
std::mutex m_maintenanceMutex;
|
||||
std::condition_variable m_maintenanceCondition;
|
||||
|
||||
const boost::program_options::variables_map& m_conf;
|
||||
|
||||
|
|
55
tests/main.cpp
Normal file
55
tests/main.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "../src/tools.h"
|
||||
#include "../src/db/driver_sqlite.hpp"
|
||||
|
||||
TEST(Utility, SanityCheck) {
|
||||
const uint32_t MAGIC = 0xDEADBEEF;
|
||||
const unsigned char MAGIC_BYTES[4] = {0xEF, 0xBE, 0xAD, 0xDE};
|
||||
ASSERT_TRUE(memcmp(&MAGIC, MAGIC_BYTES, 4) == 0);
|
||||
}
|
||||
|
||||
TEST(Utility, CheckMTON) {
|
||||
EXPECT_EQ(m_hton16(0xDEAD), 0xADDE);
|
||||
EXPECT_EQ(m_hton32(0xDEADBEEF), 0xEFBEADDE);
|
||||
EXPECT_EQ(m_hton64(0xDEADBEEFA1B2C3E4), 0xE4C3B2A1EFBEADDE);
|
||||
}
|
||||
|
||||
TEST(Utility, HashToHexStr) {
|
||||
const char EXPECTED_OUTPUT[] = "c670606edd22fd0e3b432c977559a687cc5d9bd2";
|
||||
const unsigned char DATA[20] = {198, 112, 96, 110, 221, 34, 253, 14, 59, 67, 44, 151, 117, 89, 166, 135, 204, 93, 155, 210};
|
||||
|
||||
char OUTPUT_BUFFER[41] = {0};
|
||||
to_hex_str(DATA, OUTPUT_BUFFER);
|
||||
|
||||
ASSERT_EQ(std::string(EXPECTED_OUTPUT), OUTPUT_BUFFER);
|
||||
}
|
||||
|
||||
class SQLiteDriverTest:
|
||||
public ::testing::Test {
|
||||
protected:
|
||||
SQLiteDriverTest(): va_map(), driver(nullptr) {
|
||||
va_map.insert(std::pair<std::string, boost::program_options::variable_value>("db.param", boost::program_options::variable_value(std::string(":memory:"), true)));
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
if (nullptr == driver) {
|
||||
driver = new UDPT::Data::SQLite3Driver(va_map, false);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (nullptr != driver) {
|
||||
delete driver;
|
||||
driver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
UDPT::Data::SQLite3Driver *driver;
|
||||
boost::program_options::variables_map va_map;
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
22
vs/UDPT.sln
22
vs/UDPT.sln
|
@ -1,22 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UDPT", "UDPT\UDPT.vcxproj", "{9F399AF8-861E-4E50-A94C-1388089E3FA0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9F399AF8-861E-4E50-A94C-1388089E3FA0}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9F399AF8-861E-4E50-A94C-1388089E3FA0}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9F399AF8-861E-4E50-A94C-1388089E3FA0}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9F399AF8-861E-4E50-A94C-1388089E3FA0}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,111 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{9F399AF8-861E-4E50-A94C-1388089E3FA0}</ProjectGuid>
|
||||
<RootNamespace>UDPT</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);D:\libs\sqlite3;D:\libs\boost\boost_1_59_0</IncludePath>
|
||||
<LibraryPath>D:\libs\boost\boost_1_59_0\stage\lib;D:\libs\sqlite3\Release;$(LibraryPath)</LibraryPath>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);D:\libs\sqlite3;D:\libs\boost\boost_1_59_0</IncludePath>
|
||||
<LibraryPath>D:\libs\boost\boost_1_59_0\stage\lib;D:\libs\sqlite3\Release;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;sqlite3.lib;advapi32.lib;shell32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>
|
||||
</EnableCOMDATFolding>
|
||||
<OptimizeReferences>
|
||||
</OptimizeReferences>
|
||||
<AdditionalDependencies>ws2_32.lib;sqlite3.lib;advapi32.lib;shell32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\db\database.cpp" />
|
||||
<ClCompile Include="..\..\src\db\driver_sqlite.cpp" />
|
||||
<ClCompile Include="..\..\src\http\httpserver.cpp" />
|
||||
<ClCompile Include="..\..\src\http\webapp.cpp" />
|
||||
<ClCompile Include="..\..\src\main.cpp" />
|
||||
<ClCompile Include="..\..\src\service.cpp" />
|
||||
<ClCompile Include="..\..\src\tools.c" />
|
||||
<ClCompile Include="..\..\src\tracker.cpp" />
|
||||
<ClCompile Include="..\..\src\udpTracker.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\db\database.hpp" />
|
||||
<ClInclude Include="..\..\src\db\driver_sqlite.hpp" />
|
||||
<ClInclude Include="..\..\src\exceptions.h" />
|
||||
<ClInclude Include="..\..\src\http\httpserver.hpp" />
|
||||
<ClInclude Include="..\..\src\http\webapp.hpp" />
|
||||
<ClInclude Include="..\..\src\multiplatform.h" />
|
||||
<ClInclude Include="..\..\src\service.hpp" />
|
||||
<ClInclude Include="..\..\src\tools.h" />
|
||||
<ClInclude Include="..\..\src\tracker.hpp" />
|
||||
<ClInclude Include="..\..\src\udpTracker.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,90 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\db">
|
||||
<UniqueIdentifier>{f5a85f67-2777-4fa5-828e-9c79af9f4b13}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\db">
|
||||
<UniqueIdentifier>{643f664e-8751-4440-8b90-fe95b15e0aac}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\http">
|
||||
<UniqueIdentifier>{bcb1fa9f-c9ec-4398-97f9-544baf69f2a9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\http">
|
||||
<UniqueIdentifier>{f65a2e69-6a71-4cd0-ad64-36a73c6c94c4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tools.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\udpTracker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\db\database.cpp">
|
||||
<Filter>Source Files\db</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\db\driver_sqlite.cpp">
|
||||
<Filter>Source Files\db</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\http\httpserver.cpp">
|
||||
<Filter>Source Files\http</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\http\webapp.cpp">
|
||||
<Filter>Source Files\http</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tracker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\service.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\multiplatform.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\tools.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\udpTracker.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\db\database.hpp">
|
||||
<Filter>Header Files\db</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\db\driver_sqlite.hpp">
|
||||
<Filter>Header Files\db</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\http\httpserver.hpp">
|
||||
<Filter>Header Files\http</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\http\webapp.hpp">
|
||||
<Filter>Header Files\http</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\exceptions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\tracker.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\service.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in a new issue