WIP: Added some logging to tracker
This commit is contained in:
parent
db4b8e8c81
commit
d1d879c27c
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <WS2tcpip.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif defined (linux)
|
#elif defined (linux)
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
|
@ -20,18 +20,19 @@
|
||||||
|
|
||||||
namespace UDPT
|
namespace UDPT
|
||||||
{
|
{
|
||||||
Tracker::Tracker()
|
Tracker::Tracker() : m_logger(boost::log::keywords::channel = "TRACKER")
|
||||||
{
|
{
|
||||||
|
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Initialized Tracker";
|
||||||
}
|
}
|
||||||
|
|
||||||
Tracker::~Tracker()
|
Tracker::~Tracker()
|
||||||
{
|
{
|
||||||
|
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Destroying Tracker...";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracker::stop()
|
void Tracker::stop()
|
||||||
{
|
{
|
||||||
|
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Requesting Tracker to terminate.";
|
||||||
m_udpTracker->stop();
|
m_udpTracker->stop();
|
||||||
wait();
|
wait();
|
||||||
|
|
||||||
|
@ -41,22 +42,26 @@ namespace UDPT
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracker::wait()
|
void Tracker::wait()
|
||||||
{
|
{
|
||||||
m_udpTracker->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)
|
void Tracker::start(const boost::program_options::variables_map& conf)
|
||||||
{
|
{
|
||||||
m_udpTracker = std::shared_ptr<UDPTracker>(new UDPTracker(conf));
|
BOOST_LOG_SEV(m_logger, boost::log::trivial::debug) << "Starting Tracker...";
|
||||||
|
m_udpTracker = std::shared_ptr<UDPTracker>(new UDPTracker(conf));
|
||||||
|
|
||||||
if (conf["apiserver.enable"].as<bool>())
|
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_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 = std::shared_ptr<UDPT::Server::WebApp>(new UDPT::Server::WebApp(m_apiSrv, m_udpTracker->m_conn.get(), conf));
|
||||||
m_webApp->deploy();
|
m_webApp->deploy();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_udpTracker->start();
|
m_udpTracker->start();
|
||||||
|
BOOST_LOG_SEV(m_logger, boost::log::trivial::info) << "Tracker started.";
|
||||||
}
|
}
|
||||||
|
|
||||||
Tracker& Tracker::getInstance()
|
Tracker& Tracker::getInstance()
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||||
|
|
||||||
#include "multiplatform.h"
|
#include "multiplatform.h"
|
||||||
#include "udpTracker.hpp"
|
#include "udpTracker.hpp"
|
||||||
#include "http/httpserver.hpp"
|
#include "http/httpserver.hpp"
|
||||||
|
@ -46,7 +49,8 @@ namespace UDPT
|
||||||
std::shared_ptr<UDPT::UDPTracker> m_udpTracker;
|
std::shared_ptr<UDPT::UDPTracker> m_udpTracker;
|
||||||
std::shared_ptr<UDPT::Server::HTTPServer> m_apiSrv;
|
std::shared_ptr<UDPT::Server::HTTPServer> m_apiSrv;
|
||||||
std::shared_ptr<UDPT::Server::WebApp> m_webApp;
|
std::shared_ptr<UDPT::Server::WebApp> m_webApp;
|
||||||
|
boost::log::sources::severity_channel_logger_mt<> m_logger;
|
||||||
|
|
||||||
Tracker();
|
Tracker();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,7 @@
|
||||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib> // atoi
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <list>
|
|
||||||
#include "udpTracker.hpp"
|
#include "udpTracker.hpp"
|
||||||
#include "tools.h"
|
|
||||||
#include "multiplatform.h"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace UDPT::Data;
|
using namespace UDPT::Data;
|
||||||
|
@ -34,7 +26,7 @@ using namespace UDPT::Data;
|
||||||
|
|
||||||
namespace UDPT
|
namespace UDPT
|
||||||
{
|
{
|
||||||
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf)
|
UDPTracker::UDPTracker(const boost::program_options::variables_map& conf) : m_conf(conf), m_logger(boost::log::keywords::channel = "UDPTracker")
|
||||||
{
|
{
|
||||||
this->m_allowRemotes = conf["tracker.allow_remotes"].as<bool>();
|
this->m_allowRemotes = conf["tracker.allow_remotes"].as<bool>();
|
||||||
this->m_allowIANA_IPs = conf["tracker.allow_iana_ips"].as<bool>();
|
this->m_allowIANA_IPs = conf["tracker.allow_iana_ips"].as<bool>();
|
||||||
|
@ -67,7 +59,6 @@ namespace UDPT
|
||||||
|
|
||||||
void UDPTracker::start()
|
void UDPTracker::start()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
int r, // saves results
|
int r, // saves results
|
||||||
i, // loop index
|
i, // loop index
|
||||||
|
@ -105,15 +96,12 @@ namespace UDPT
|
||||||
::closesocket(sock);
|
::closesocket(sock);
|
||||||
#elif defined (linux)
|
#elif defined (linux)
|
||||||
::close(sock);
|
::close(sock);
|
||||||
#endif
|
#endif
|
||||||
throw UDPT::UDPTException("Failed to bind socket.");
|
throw UDPT::UDPTException("Failed to bind socket.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_sock = sock;
|
this->m_sock = sock;
|
||||||
|
|
||||||
ss.str("");
|
|
||||||
ss << "Starting maintenance thread (1/" << ((int)this->m_threadCount) << ")";
|
|
||||||
|
|
||||||
// create maintainer thread.
|
// create maintainer thread.
|
||||||
|
|
||||||
m_threads.push_back(boost::thread(UDPTracker::_maintainance_start, this));
|
m_threads.push_back(boost::thread(UDPTracker::_maintainance_start, this));
|
||||||
|
@ -132,6 +120,7 @@ namespace UDPT
|
||||||
::closesocket(m_sock);
|
::closesocket(m_sock);
|
||||||
#endif
|
#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)
|
for (std::vector<boost::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
{
|
{
|
||||||
it->interrupt();
|
it->interrupt();
|
||||||
|
@ -142,6 +131,8 @@ namespace UDPT
|
||||||
|
|
||||||
void UDPTracker::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)
|
for (std::vector<boost::thread>::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||||
{
|
{
|
||||||
it->join();
|
it->join();
|
||||||
|
@ -193,38 +184,43 @@ namespace UDPT
|
||||||
|
|
||||||
::sendto(usi->m_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));
|
||||||
|
|
||||||
|
{
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UDPTracker::handleAnnounce (UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
int UDPTracker::handleAnnounce(UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
||||||
{
|
{
|
||||||
AnnounceRequest *req;
|
AnnounceRequest *req;
|
||||||
AnnounceResponse *resp;
|
AnnounceResponse *resp;
|
||||||
int q, // peer counts
|
int q, // peer counts
|
||||||
bSize, // message size
|
bSize, // message size
|
||||||
i; // loop index
|
i; // loop index
|
||||||
DatabaseDriver::PeerEntry *peers;
|
|
||||||
DatabaseDriver::TorrentEntry tE;
|
DatabaseDriver::TorrentEntry tE;
|
||||||
|
|
||||||
uint8_t buff [1028]; // Reasonable buffer size. (header+168 peers)
|
uint8_t buff[1028]; // Reasonable buffer size. (header+168 peers)
|
||||||
|
|
||||||
req = (AnnounceRequest*)data;
|
req = (AnnounceRequest*)data;
|
||||||
|
|
||||||
if (!usi->m_conn->verifyConnectionId(req->connection_id,
|
if (!usi->m_conn->verifyConnectionId(req->connection_id,
|
||||||
m_hton32(remote->sin_addr.s_addr),
|
m_hton32(remote->sin_addr.s_addr),
|
||||||
m_hton16(remote->sin_port)))
|
m_hton16(remote->sin_port)))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// change byte order:
|
// change byte order:
|
||||||
req->port = m_hton16 (req->port);
|
req->port = m_hton16(req->port);
|
||||||
req->ip_address = m_hton32 (req->ip_address);
|
req->ip_address = m_hton32(req->ip_address);
|
||||||
req->downloaded = m_hton64 (req->downloaded);
|
req->downloaded = m_hton64(req->downloaded);
|
||||||
req->event = m_hton32 (req->event); // doesn't really matter for this tracker
|
req->event = m_hton32(req->event); // doesn't really matter for this tracker
|
||||||
req->uploaded = m_hton64 (req->uploaded);
|
req->uploaded = m_hton64(req->uploaded);
|
||||||
req->num_want = m_hton32 (req->num_want);
|
req->num_want = m_hton32(req->num_want);
|
||||||
req->left = m_hton64 (req->left);
|
req->left = m_hton64(req->left);
|
||||||
|
|
||||||
if (!usi->m_allowRemotes && req->ip_address != 0)
|
if (!usi->m_allowRemotes && req->ip_address != 0)
|
||||||
{
|
{
|
||||||
|
@ -243,62 +239,64 @@ namespace UDPT
|
||||||
if (req->num_want >= 1)
|
if (req->num_want >= 1)
|
||||||
q = std::min<int>(q, req->num_want);
|
q = std::min<int>(q, req->num_want);
|
||||||
|
|
||||||
peers = new DatabaseDriver::PeerEntry [q];
|
|
||||||
|
|
||||||
|
|
||||||
DatabaseDriver::TrackerEvents event;
|
DatabaseDriver::TrackerEvents event;
|
||||||
switch (req->event)
|
|
||||||
{
|
{
|
||||||
case 1:
|
std::shared_ptr<DatabaseDriver::PeerEntry> peersSptr = std::shared_ptr<DatabaseDriver::PeerEntry>(new DatabaseDriver::PeerEntry[q]);
|
||||||
event = DatabaseDriver::EVENT_COMPLETE;
|
DatabaseDriver::PeerEntry *peers = peersSptr.get();
|
||||||
break;
|
|
||||||
case 2:
|
switch (req->event)
|
||||||
event = DatabaseDriver::EVENT_START;
|
{
|
||||||
break;
|
case 1:
|
||||||
case 3:
|
event = DatabaseDriver::EVENT_COMPLETE;
|
||||||
event = DatabaseDriver::EVENT_STOP;
|
break;
|
||||||
break;
|
case 2:
|
||||||
default:
|
event = DatabaseDriver::EVENT_START;
|
||||||
event = DatabaseDriver::EVENT_UNSPEC;
|
break;
|
||||||
break;
|
case 3:
|
||||||
|
event = DatabaseDriver::EVENT_STOP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
event = DatabaseDriver::EVENT_UNSPEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == DatabaseDriver::EVENT_STOP)
|
||||||
|
q = 0; // no need for peers when stopping.
|
||||||
|
|
||||||
|
if (q > 0)
|
||||||
|
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->m_conn->getTorrentInfo(&tE);
|
||||||
|
|
||||||
|
resp = (AnnounceResponse*)buff;
|
||||||
|
resp->action = m_hton32(1);
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (i = 0; i < q; i++)
|
||||||
|
{
|
||||||
|
int x = i * 6;
|
||||||
|
// network byte order!!!
|
||||||
|
|
||||||
|
// IP
|
||||||
|
buff[20 + x] = ((peers[i].ip & (0xff << 24)) >> 24);
|
||||||
|
buff[21 + x] = ((peers[i].ip & (0xff << 16)) >> 16);
|
||||||
|
buff[22 + x] = ((peers[i].ip & (0xff << 8)) >> 8);
|
||||||
|
buff[23 + x] = (peers[i].ip & 0xff);
|
||||||
|
|
||||||
|
// port
|
||||||
|
buff[24 + x] = ((peers[i].port & (0xff << 8)) >> 8);
|
||||||
|
buff[25 + x] = (peers[i].port & 0xff);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == DatabaseDriver::EVENT_STOP)
|
|
||||||
q = 0; // no need for peers when stopping.
|
|
||||||
|
|
||||||
if (q > 0)
|
|
||||||
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->m_conn->getTorrentInfo(&tE);
|
|
||||||
|
|
||||||
resp = (AnnounceResponse*)buff;
|
|
||||||
resp->action = m_hton32(1);
|
|
||||||
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;
|
|
||||||
|
|
||||||
for (i = 0;i < q;i++)
|
|
||||||
{
|
|
||||||
int x = i * 6;
|
|
||||||
// network byte order!!!
|
|
||||||
|
|
||||||
// IP
|
|
||||||
buff[20 + x] = ((peers[i].ip & (0xff << 24)) >> 24);
|
|
||||||
buff[21 + x] = ((peers[i].ip & (0xff << 16)) >> 16);
|
|
||||||
buff[22 + x] = ((peers[i].ip & (0xff << 8)) >> 8);
|
|
||||||
buff[23 + x] = (peers[i].ip & 0xff);
|
|
||||||
|
|
||||||
// port
|
|
||||||
buff[24 + x] = ((peers[i].port & (0xff << 8)) >> 8);
|
|
||||||
buff[25 + x] = (peers[i].port & 0xff);
|
|
||||||
|
|
||||||
}
|
|
||||||
delete[] peers;
|
|
||||||
::sendto(usi->m_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.
|
// update DB.
|
||||||
|
@ -396,10 +394,18 @@ namespace UDPT
|
||||||
{
|
{
|
||||||
if (isIANAIP(remote->sin_addr.s_addr))
|
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));
|
||||||
return 0; // Access Denied: IANA reserved IP.
|
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)
|
if (action == 0 && r >= 16)
|
||||||
return UDPTracker::handleConnection(usi, remote, data);
|
return UDPTracker::handleConnection(usi, remote, data);
|
||||||
else if (action == 1 && r >= 98)
|
else if (action == 1 && r >= 98)
|
||||||
|
@ -417,6 +423,7 @@ namespace UDPT
|
||||||
|
|
||||||
void UDPTracker::_thread_start(UDPTracker *usi)
|
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() << ".";
|
||||||
SOCKADDR_IN remoteAddr;
|
SOCKADDR_IN remoteAddr;
|
||||||
char tmpBuff[UDP_BUFFER_SIZE];
|
char tmpBuff[UDP_BUFFER_SIZE];
|
||||||
|
|
||||||
|
@ -441,17 +448,20 @@ namespace UDPT
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::this_thread::disable_interruption di;
|
boost::this_thread::disable_interruption di;
|
||||||
r = UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r);
|
|
||||||
|
UDPTracker::resolveRequest(usi, &remoteAddr, tmpBuff, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPTracker::_maintainance_start(UDPTracker* usi)
|
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() << ".";
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
boost::this_thread::disable_interruption di;
|
boost::this_thread::disable_interruption di;
|
||||||
|
BOOST_LOG_SEV(usi->m_logger, boost::log::trivial::info) << "Running cleanup...";
|
||||||
usi->m_conn->cleanup();
|
usi->m_conn->cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,19 @@
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <list>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "multiplatform.h"
|
#include "multiplatform.h"
|
||||||
#include "db/driver_sqlite.hpp"
|
#include "db/driver_sqlite.hpp"
|
||||||
|
@ -155,6 +163,7 @@ namespace UDPT
|
||||||
std::vector<boost::thread> m_threads;
|
std::vector<boost::thread> m_threads;
|
||||||
uint32_t m_announceInterval;
|
uint32_t m_announceInterval;
|
||||||
uint32_t m_cleanupInterval;
|
uint32_t m_cleanupInterval;
|
||||||
|
boost::log::sources::severity_channel_logger_mt<> m_logger;
|
||||||
|
|
||||||
const boost::program_options::variables_map& m_conf;
|
const boost::program_options::variables_map& m_conf;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue