New Database Interface,

The Ability to add more Database Drivers.
This commit is contained in:
Naim A 2013-03-04 00:54:48 +02:00
parent 51e2c80ba7
commit d1c49c6b6f
8 changed files with 860 additions and 511 deletions

121
src/db/database.cpp Normal file
View file

@ -0,0 +1,121 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "database.hpp"
namespace UDPT
{
namespace Data
{
DatabaseDriver::DatabaseDriver(Settings::SettingClass *sc, bool isDynamic)
{
this->dClass = sc;
this->is_dynamic = isDynamic;
}
bool DatabaseDriver::addTorrent(uint8_t hash [20])
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::removeTorrent(uint8_t hash[20])
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::isDynamic()
{
return this->is_dynamic;
}
bool DatabaseDriver::genConnectionId(uint64_t *cid, uint32_t ip, uint16_t port)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::verifyConnectionId(uint64_t cid, uint32_t ip, uint16_t port)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::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)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::removePeer (uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::getTorrentInfo (TorrentEntry *e)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::getPeers (uint8_t info_hash [20], int *max_count, PeerEntry *pe)
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
void DatabaseDriver::cleanup()
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
bool DatabaseDriver::isTorrentAllowed(uint8_t info_hash[20])
{
throw DatabaseException (DatabaseException::E_NOT_IMPLEMENTED);
}
DatabaseDriver::~DatabaseDriver()
{
}
/*-- Exceptions --*/
static const char *EMessages[] = {
"Unknown Error",
"Not Implemented",
"Failed to connect to database"
};
DatabaseException::DatabaseException()
{
this->errorNum = E_UNKNOWN;
}
DatabaseException::DatabaseException(enum EType e)
{
this->errorNum = e;
}
enum DatabaseException::EType DatabaseException::getErrorType()
{
return this->errorNum;
}
const char* DatabaseException::getErrorMessage()
{
return EMessages[this->errorNum];
}
};
};

View file

@ -1,105 +0,0 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DATABASE_H_
#define DATABASE_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dbConnection dbConnection;
/**
* Opens a database connection.
* @param pdb Pointer to database instance.
* @param cStr Connection string for the active driver.
* @return 0 on success; otherwise non-zero.
*/
int db_open (dbConnection **pdb, const char *cStr);
/**
* Closes the database connection.
* @param db Database instance.
* @return 0 on success; otherwise non-zero.
*/
int db_close (dbConnection *db);
typedef struct {
uint8_t *peer_id;
uint64_t downloaded;
uint64_t uploaded;
uint64_t left;
uint32_t ip; // currently only support IPv4.
uint16_t port;
} db_peerEntry;
/**
* Adds/Updates the list of peers.
* @param db The database's instance.
* @param hash The info_hash of the torrent.
* @param pE Peer's information.
* @return 0 on success; otherwise non-zero.
*/
int db_add_peer (dbConnection *db, uint8_t hash[20], db_peerEntry *pE);
/**
* Loads peers for the requested torrent.
* @param db Database instance.
* @param hash The info_hash of the requested torrent.
* @param lst A allocated array to store results in.
* @param sZ in: The maximum amount of entries to load. out: Amount of loaded entries.
* @return 0 on success; otherwise non-zero.
*/
int db_load_peers (dbConnection *db, uint8_t hash[20], db_peerEntry *lst, int *sZ);
/**
* Gets stats for the requested torrent.
* @param db The Database connection
* @param hash info_hash of the torrent.
* @param seeders Returns the Seeders for the requested torrent.
* @param leechers Returns the Leechers for the requested torrent.
* @param completed Returns the count of completed downloaded reported.
* @return 0 on success, otherwise non-zero.
*/
int db_get_stats (dbConnection *db, uint8_t hash[20], int32_t *seeders, int32_t *leechers, int32_t *completed);
/**
* Maintenance routine, Calculates stats & releases space from old entries.
* @param db The database connection.
* @return 0 on success; otherwise non-zero.
*/
int db_cleanup (dbConnection *db);
/**
* Deletes a peer from the database.
* @param db Database connection
* @param hash info_hash of the torrent.
* @param pE The peer's information.
* @return 0 on success; otherwise non-zero.
*/
int db_remove_peer (dbConnection *db, uint8_t hash [20], db_peerEntry *pE);
#ifdef __cplusplus
}
#endif
#endif /* DATABASE_H_ */

173
src/db/database.hpp Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DATABASE_HPP_
#define DATABASE_HPP_
#include "../settings.hpp"
namespace UDPT
{
namespace Data
{
class DatabaseException
{
public:
enum EType {
E_UNKNOWN = 0, // Unknown error
E_NOT_IMPLEMENTED = 1, // not implemented
E_CONNECTION_FAILURE = 2
};
DatabaseException ();
DatabaseException (EType);
EType getErrorType ();
const char* getErrorMessage ();
private:
EType errorNum;
};
class DatabaseDriver
{
public:
typedef struct {
uint8_t *info_hash;
int32_t seeders;
int32_t leechers;
int32_t completed;
} TorrentEntry;
typedef struct {
uint32_t ip;
uint16_t port;
} PeerEntry;
enum TrackerEvents {
EVENT_UNSPEC = 0,
EVENT_COMPLETE = 1,
EVENT_START = 2,
EVENT_STOP = 3
};
/**
* Opens the DB's connection
* @param dClass Settings class ('database' class).
*/
DatabaseDriver (Settings::SettingClass *dClass, 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]);
/**
* 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]);
/**
* Checks if the Database is acting as a dynamic tracker DB.
* @return true if dynamic. otherwise false.
*/
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]);
/**
* Generate a Connection ID for the peer.
* @param connectionId (Output) the generated connection ID.
* @param ip The peer's IP (requesting peer. not remote)
* @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 verifyConnectionId (uint64_t connectionId, uint32_t ip, uint16_t port);
/**
* Updates/Adds a peer to/in the database.
* @param peer_id the peer's peer_id
* @param info_hash the torrent info_hash
* @param ip IP of peer (remote ip if tracker accepts)
* @param port TCP port of peer (remote port if tracker accepts)
* @param downloaded total Bytes downloaded
* @param left total bytes left
* @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],
uint32_t ip, uint16_t port,
int64_t downloaded, int64_t left, int64_t uploaded,
enum TrackerEvents event);
/**
* Remove a peer from a torrent (if stop action occurred, or if peer is inactive in cleanup)
* @param peer_id The peer's peer_id
* @param info_hash Torrent's info_hash
* @param ip The IP of the peer (remote IP if tracker accepts)
* @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);
/**
* 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);
/**
* Gets a list of peers from the database.
* @param info_hash The torrent's info_hash
* @param max_count The maximum amount of peers to load from the database. The amount of loaded peers is returned through this variable.
* @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);
/**
* Cleanup the database.
* Other actions may be locked when using this depending on the driver.
*/
virtual void cleanup ();
/**
* Closes the connections, and releases all other resources.
*/
virtual ~DatabaseDriver ();
protected:
Settings::SettingClass *dClass;
private:
bool is_dynamic;
};
};
};
#endif /* DATABASE_HPP_ */

View file

@ -1,343 +0,0 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "database.h"
#include "../multiplatform.h"
#include "../tools.h"
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
struct dbConnection
{
sqlite3 *db;
HANDLE janitor;
};
static const char hexadecimal[] = "0123456789abcdef";
void _to_hex_str (const uint8_t *hash, char *data)
{
int i;
for (i = 0;i < 20;i++)
{
data[i * 2] = hexadecimal[hash[i] / 16];
data[i * 2 + 1] = hexadecimal[hash[i] % 16];
}
data[40] = '\0';
}
static int _db_make_torrent_table (sqlite3 *db, char *hash)
{
char sql [2000];
char *err_msg;
int r;
sql[0] = '\0';
strcat(sql, "CREATE TABLE IF NOT EXISTS 't");
strcat(sql, hash);
strcat (sql, "' (");
strcat (sql, "peer_id blob(20),"
"ip blob(4),"
"port blob(2),"
"uploaded blob(8)," // uint64
"downloaded blob(8),"
"left blob(8),"
"last_seen INT DEFAULT 0");
strcat(sql, ", CONSTRAINT c1 UNIQUE (ip,port) ON CONFLICT REPLACE)");
// create table.
r = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
printf("E:%s\n", err_msg);
return r;
}
static void _db_setup (sqlite3 *db)
{
sqlite3_exec(db, "CREATE TABLE stats ("
"info_hash blob(20) UNIQUE,"
"completed INTEGER DEFAULT 0,"
"leechers INTEGER DEFAULT 0,"
"seeders INTEGER DEFAULT 0,"
"last_mod INTEGER DEFAULT 0"
")", NULL, NULL, NULL);
}
int db_open (dbConnection **db, const char *cStr)
{
FILE *f;
int doSetup, // check if to build DB, or it already exists?
r;
f = fopen (cStr, "rb");
doSetup = 0;
if (f == NULL)
doSetup = 1;
else
fclose (f);
*db = malloc (sizeof(struct dbConnection));
r = sqlite3_open (cStr, &((*db)->db));
if (doSetup)
_db_setup((*db)->db);
return r;
}
int db_close (dbConnection *db)
{
int r = sqlite3_close(db->db);
free (db);
return r;
}
int db_add_peer (dbConnection *db, uint8_t info_hash[20], db_peerEntry *pE)
{
char xHash [50]; // we just need 40 + \0 = 41.
sqlite3_stmt *stmt;
char sql [1000];
int r;
char *hash = xHash;
to_hex_str(info_hash, hash);
_db_make_torrent_table(db->db, hash);
sql[0] = '\0';
strcat(sql, "REPLACE INTO 't");
strcat(sql, hash);
strcat(sql, "' (peer_id,ip,port,uploaded,downloaded,left,last_seen) VALUES (?,?,?,?,?,?,?)");
// printf("IP->%x::%u\n", pE->ip, pE->port);
sqlite3_prepare(db->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 1, (void*)pE->peer_id, 20, NULL);
sqlite3_bind_blob(stmt, 2, (void*)&pE->ip, 4, NULL);
sqlite3_bind_blob(stmt, 3, (void*)&pE->port, 2, NULL);
sqlite3_bind_blob(stmt, 4, (void*)&pE->uploaded, 8, NULL);
sqlite3_bind_blob(stmt, 5, (void*)&pE->downloaded, 8, NULL);
sqlite3_bind_blob(stmt, 6, (void*)&pE->left, 8, NULL);
sqlite3_bind_int(stmt, 7, time(NULL));
r = sqlite3_step(stmt);
sqlite3_finalize(stmt);
strcpy(sql, "REPLACE INTO stats (info_hash,last_mod) VALUES (?,?)");
sqlite3_prepare (db->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob (stmt, 1, hash, 20, NULL);
sqlite3_bind_int (stmt, 2, time(NULL));
sqlite3_step (stmt);
sqlite3_finalize (stmt);
return r;
}
int db_load_peers (dbConnection *db, uint8_t info_hash[20], db_peerEntry *lst, int *sZ)
{
char sql [1000];
char hash [50];
sqlite3_stmt *stmt;
int r,
i;
sql[0] = '\0';
to_hex_str(info_hash, hash);
strcat(sql, "SELECT ip,port FROM 't");
strcat(sql, hash);
strcat(sql, "' LIMIT ?");
sqlite3_prepare(db->db, sql, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, *sZ);
i = 0;
while (*sZ > i)
{
r = sqlite3_step(stmt);
if (r == SQLITE_ROW)
{
const char *ip = (const char*)sqlite3_column_blob (stmt, 0);
const char *port = (const char*)sqlite3_column_blob (stmt, 1);
memcpy(&lst[i].ip, ip, 4);
memcpy(&lst[i].port, port, 2);
i++;
}
else
break;
}
printf("%d Clients Dumped.\n", i);
sqlite3_finalize(stmt);
*sZ = i;
return 0;
}
int db_get_stats (dbConnection *db, uint8_t hash[20], int32_t *seeders, int32_t *leechers, int32_t *completed)
{
const char sql[] = "SELECT seeders,leechers,completed FROM 'stats' WHERE info_hash=?";
sqlite3_stmt *stmt;
*seeders = 0;
*leechers = 0;
*completed = 0;
sqlite3_prepare (db->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob (stmt, 1, (void*)hash, 20, NULL);
if (sqlite3_step(stmt) == SQLITE_ROW)
{
*seeders = sqlite3_column_int (stmt, 0);
*leechers = sqlite3_column_int (stmt, 1);
*completed = sqlite3_column_int (stmt, 2);
}
sqlite3_finalize (stmt);
return 0;
}
int db_cleanup (dbConnection *db)
{
const char sql[] = "SELECT info_hash FROM stats WHERE last_mod<?";
char hash [50],
temp [1000];
sqlite3_stmt *stmt;
int timeframe;
uint32_t leechers, seeders;
sqlite3_stmt *sTmp, *uStat;
return 0; // TODO: Fix problems and than allow use of this function.
printf("Cleanup...\n");
timeframe = time(NULL);
// remove "dead" torrents (non-active for two hours).
sqlite3_prepare (db->db, sql, -1, &stmt, NULL);
sqlite3_bind_int (stmt, 1, timeframe - 7200);
while (sqlite3_step(stmt) == SQLITE_ROW)
{
to_hex_str(sqlite3_column_blob(stmt, 0), hash);
// drop table:
strcpy(temp, "DROP TABLE IF EXISTS 't");
strcat(temp, hash);
strcat(temp, "'");
sqlite3_exec(db->db, temp, NULL, NULL, NULL);
}
sqlite3_finalize (stmt);
// update 'dead' torrents
sqlite3_prepare(db->db, "UPDATE stats SET seeders=0,leechers=0 WHERE last_mod<?", -1, &stmt, NULL);
sqlite3_bind_int (stmt, 1, timeframe - 7200);
sqlite3_step (stmt);
sqlite3_finalize (stmt);
// update regular torrents.
sqlite3_prepare(db->db, "SELECT info_hash FROM stats WHERE last_mod>=?", -1, &stmt, NULL);
sqlite3_bind_int (stmt, 1, timeframe - 7200);
sqlite3_prepare (db->db, "UPDATE stats SET seeders=?,leechers=?,last_mod=? WHERE info_hash=?", -1, &uStat, NULL);
while (sqlite3_step(stmt) == SQLITE_ROW)
{
uint8_t *binHash = (uint8_t*)sqlite3_column_blob(stmt, 0);
to_hex_str (binHash, hash);
// total users...
strcpy (temp, "SELECT COUNT(*) FROM 't");
strcat (temp, hash);
strcat (temp, "'");
sqlite3_prepare (db->db, temp, -1, &sTmp, NULL);
if (sqlite3_step(sTmp) == SQLITE_ROW)
{
leechers = sqlite3_column_int (sTmp, 0);
}
sqlite3_finalize (sTmp);
// seeders...
strcpy (temp, "SELECT COUNT(*) FROM 't");
strcat (temp, hash);
strcat (temp, "' WHERE left=0");
sqlite3_prepare (db->db, temp, -1, &sTmp, NULL);
if (sqlite3_step(sTmp) == SQLITE_ROW)
{
seeders = sqlite3_column_int (sTmp, 0);
}
sqlite3_finalize (sTmp);
leechers -= seeders;
sqlite3_bind_int (uStat, 1, seeders);
sqlite3_bind_int (uStat, 2, leechers);
sqlite3_bind_int (uStat, 3, timeframe);
sqlite3_bind_blob (uStat, 4, binHash, 20, NULL);
sqlite3_step (uStat);
sqlite3_reset (uStat);
printf("%s: %d seeds/%d leechers;\n", hash, seeders, leechers);
}
sqlite3_finalize (stmt);
sqlite3_finalize (stmt);
return 0;
}
int db_remove_peer (dbConnection *db, uint8_t hash[20], db_peerEntry *pE)
{
char sql [1000];
char xHash [50];
sqlite3_stmt *stmt;
_to_hex_str (hash, xHash);
strcpy (sql, "DELETE FROM 't");
strcat (sql, xHash);
strcat (sql, "' WHERE ip=? AND port=? AND peer_id=?");
sqlite3_prepare (db->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 0, (const void*)&pE->ip, 4, NULL);
sqlite3_bind_blob(stmt, 1, (const void*)&pE->port, 2, NULL);
sqlite3_bind_blob(stmt, 2, (const void*)pE->peer_id, 20, NULL);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
return 0;
}

430
src/db/driver_sqlite.cpp Normal file
View file

@ -0,0 +1,430 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "driver_sqlite.hpp"
#include "../multiplatform.h"
#include "../tools.h"
#include <sqlite3.h>
#include <time.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cassert>
using namespace std;
namespace UDPT
{
namespace Data
{
static const char hexadecimal[] = "0123456789abcdef";
static char* _to_hex_str (const uint8_t *hash, char *data)
{
int i;
for (i = 0;i < 20;i++)
{
data[i * 2] = hexadecimal[hash[i] / 16];
data[i * 2 + 1] = hexadecimal[hash[i] % 16];
}
data[40] = '\0';
return data;
}
static uint8_t* _hash_to_bin (const char *hash, uint8_t *data)
{
for (int i = 0;i < 20;i++)
{
data [i] = 0;
char a = hash[i * 2];
char b = hash[i * 2 + 1];
assert ( (a >= 'a' && a <= 'f') || (a >= '0' && a <= '9') );
assert ( (b >= 'a' && b <= 'f') || (b >= '0' && b <= '9') );
data[i] = ( (a >= '0' && a <= 'f') ? (a - '0') : (a - 'f' + 10) );
data[i] <<= 4;
data[i] = ( (b >= '0' && b <= 'f') ? (b - '0') : (b - 'f' + 10) );
}
return data;
}
SQLite3Driver::SQLite3Driver (Settings::SettingClass *sc, bool isDyn) : DatabaseDriver(sc, isDyn)
{
int r;
bool doSetup;
fstream fCheck;
string filename = sc->get("file");
fCheck.open(filename.c_str(), ios::binary | ios::in);
if (fCheck.is_open())
{
doSetup = false;
fCheck.close();
}
else
doSetup = true;
r = sqlite3_open(filename.c_str(), &this->db);
if (r != SQLITE_OK)
{
sqlite3_close(this->db);
throw DatabaseException (DatabaseException::E_CONNECTION_FAILURE);
}
if (doSetup)
this->doSetup();
}
void SQLite3Driver::doSetup()
{
// cout << "Creating DB..." << endl;
char *eMsg = NULL;
// for quicker stats.
sqlite3_exec(this->db, "CREATE TABLE stats ("
"info_hash blob(20) UNIQUE,"
"completed INTEGER DEFAULT 0,"
"leechers INTEGER DEFAULT 0,"
"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)
{
bool gotInfo = false;
const char sql[] = "SELECT seeders,leechers,completed FROM 'stats' WHERE info_hash=?";
sqlite3_stmt *stmt;
e->seeders = 0;
e->leechers = 0;
e->completed = 0;
sqlite3_prepare (this->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob (stmt, 1, (void*)e->info_hash, 20, NULL);
if (sqlite3_step(stmt) == SQLITE_ROW)
{
e->seeders = sqlite3_column_int (stmt, 0);
e->leechers = sqlite3_column_int (stmt, 1);
e->completed = sqlite3_column_int (stmt, 2);
gotInfo = true;
}
sqlite3_finalize (stmt);
return gotInfo;
}
bool SQLite3Driver::getPeers (uint8_t info_hash [20], int *max_count, PeerEntry *pe)
{
char sql [1000];
char hash [50];
sqlite3_stmt *stmt;
int r,
i;
sql[0] = '\0';
to_hex_str(info_hash, hash);
strcat(sql, "SELECT ip,port FROM 't");
strcat(sql, hash);
strcat(sql, "' LIMIT ?");
sqlite3_prepare(this->db, sql, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, *max_count);
i = 0;
while (*max_count > i)
{
r = sqlite3_step(stmt);
if (r == SQLITE_ROW)
{
const char *ip = (const char*)sqlite3_column_blob (stmt, 0);
const char *port = (const char*)sqlite3_column_blob (stmt, 1);
memcpy(&pe[i].ip, ip, 4);
memcpy(&pe[i].port, port, 2);
i++;
}
else
{
break;
}
}
printf("%d Clients Dumped.\n", i);
sqlite3_finalize(stmt);
*max_count = i;
return true;
}
bool SQLite3Driver::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)
{
char xHash [50]; // we just need 40 + \0 = 41.
sqlite3_stmt *stmt;
char sql [1000];
int r;
char *hash = xHash;
to_hex_str(info_hash, hash);
addTorrent (info_hash);
sql[0] = '\0';
strcat(sql, "REPLACE INTO 't");
strcat(sql, hash);
strcat(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, -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 1, (void*)peer_id, 20, NULL);
sqlite3_bind_blob(stmt, 2, (void*)&ip, 4, NULL);
sqlite3_bind_blob(stmt, 3, (void*)&port, 2, NULL);
sqlite3_bind_blob(stmt, 4, (void*)&uploaded, 8, NULL);
sqlite3_bind_blob(stmt, 5, (void*)&downloaded, 8, NULL);
sqlite3_bind_blob(stmt, 6, (void*)&left, 8, NULL);
sqlite3_bind_int(stmt, 7, time(NULL));
r = sqlite3_step(stmt);
sqlite3_finalize(stmt);
strcpy(sql, "REPLACE INTO stats (info_hash,last_mod) VALUES (?,?)");
sqlite3_prepare (this->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob (stmt, 1, hash, 20, NULL);
sqlite3_bind_int (stmt, 2, time(NULL));
sqlite3_step (stmt);
sqlite3_finalize (stmt);
return r;
}
bool SQLite3Driver::addTorrent (uint8_t info_hash[20])
{
char xHash [41];
char *err_msg;
int r;
_to_hex_str(info_hash, xHash);
// if non-dynamic, called only when adding to DB.
if (!this->isDynamic())
{
sqlite3_stmt *stmt;
sqlite3_prepare(this->db, "INSERT INTO torrents (info_hash,created) VALUES (?,?)", -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 1, info_hash, 20, NULL);
sqlite3_bind_int(stmt, 1, time(NULL));
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
string sql = "CREATE TABLE IF NOT EXISTS 't";
sql += xHash;
sql += "' (";
sql += "peer_id blob(20),"
"ip blob(4),"
"port blob(2),"
"uploaded blob(8)," // uint64
"downloaded blob(8),"
"left blob(8),"
"last_seen INT DEFAULT 0";
sql += ", CONSTRAINT c1 UNIQUE (ip,port) ON CONFLICT REPLACE)";
// create table.
r = sqlite3_exec(this->db, sql.c_str(), NULL, NULL, &err_msg);
printf("E:%s\n", err_msg);
return (r == SQLITE_OK);
}
bool SQLite3Driver::isTorrentAllowed(uint8_t info_hash[20])
{
if (this->isDynamic())
return true;
sqlite3_stmt *stmt;
sqlite3_prepare(this->db, "SELECT COUNT(*) FROM torrents WHERE info_hash=?", -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 1, info_hash, 20, NULL);
sqlite3_step(stmt);
int n = sqlite3_column_int(stmt, 1);
sqlite3_finalize(stmt);
return (n == 1);
}
void SQLite3Driver::cleanup()
{
int exp = time (NULL) - 7200; // 2 hours, expired.
// 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);
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);
while (sqlite3_step(getTables) == SQLITE_ROW)
{
char* tblN = (char*)sqlite3_column_text(getTables, 0);
stringstream sStr;
sStr << "DELETE FROM " << tblN << " WHERE last_seen<" << exp;
assert (sqlite3_exec(this->db, sStr.str().c_str(), NULL, NULL, NULL) == SQLITE_OK);
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);
cout << "[" << sqlite3_errmsg(this->db) << "]" << endl;
int seeders = 0, leechers = 0;
while (sqlite3_step(collectStats) == SQLITE_ROW) // expecting two results.
{
if (sqlite3_column_int(collectStats, 0) == 0)
seeders = sqlite3_column_int (collectStats, 1);
else
leechers = sqlite3_column_int (collectStats, 1);
}
sqlite3_finalize(collectStats);
sqlite3_bind_blob(updateStats, 1, _hash_to_bin((const char*)(tblN + 1), buff), 20, NULL);
sqlite3_bind_int(updateStats, 2, seeders);
sqlite3_bind_int(updateStats, 3, leechers);
sqlite3_bind_int(updateStats, 4, time (NULL));
sqlite3_step(updateStats);
sqlite3_reset (updateStats);
}
sqlite3_finalize(updateStats);
sqlite3_finalize(getTables);
}
bool SQLite3Driver::removeTorrent(uint8_t info_hash[20])
{
// if non-dynamic, remove from table
if (!this->isDynamic())
{
sqlite3_stmt *stmt;
sqlite3_prepare(this->db, "DELETE FROM torrents WHERE info_hash=?", -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 1, info_hash, 20, NULL);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
// remove from stats
sqlite3_stmt *rmS;
if (sqlite3_prepare(this->db, "DELETE FROM stats WHERE info_hash=?", -1, &rmS, NULL) != SQLITE_OK)
{
sqlite3_finalize(rmS);
return false;
}
sqlite3_bind_blob(rmS, 1, (const void*)info_hash, 20, NULL);
sqlite3_step(rmS);
sqlite3_finalize(rmS);
// remove table
string str = "DROP TABLE IF EXISTS 't";
char buff [41];
str += _to_hex_str(info_hash, buff);
str += "'";
sqlite3_exec(this->db, str.c_str(), NULL, NULL, NULL);
return true;
}
bool SQLite3Driver::removePeer(uint8_t peer_id [20], uint8_t info_hash [20], uint32_t ip, uint16_t port)
{
char sql [1000];
char xHash [50];
sqlite3_stmt *stmt;
_to_hex_str (info_hash, xHash);
strcpy (sql, "DELETE FROM 't");
strcat (sql, xHash);
strcat (sql, "' WHERE ip=? AND port=? AND peer_id=?");
sqlite3_prepare (this->db, sql, -1, &stmt, NULL);
sqlite3_bind_blob(stmt, 0, (const void*)&ip, 4, NULL);
sqlite3_bind_blob(stmt, 1, (const void*)&port, 2, NULL);
sqlite3_bind_blob(stmt, 2, (const void*)peer_id, 20, NULL);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
return true;
}
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);
x <<= 16;
x |= (~port);
return x;
}
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)
{
if (cId == _genCiD(ip, port))
return true;
else
return false;
}
SQLite3Driver::~SQLite3Driver()
{
sqlite3_close(this->db);
}
};
};

55
src/db/driver_sqlite.hpp Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright © 2012,2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UDPT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DATABASE_H_
#define DATABASE_H_
#include <stdint.h>
#include "database.hpp"
#include <sqlite3.h>
namespace UDPT
{
namespace Data
{
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 ();
private:
sqlite3 *db;
void doSetup ();
};
};
};
#endif /* DATABASE_H_ */

View file

@ -25,6 +25,7 @@
#include <iostream> #include <iostream>
using namespace std; using namespace std;
using namespace UDPT::Data;
#define UDP_BUFFER_SIZE 2048 #define UDP_BUFFER_SIZE 2048
@ -91,8 +92,6 @@ namespace UDPT
this->port = (s_port == "" ? 6969 : atoi (s_port.c_str())); this->port = (s_port == "" ? 6969 : atoi (s_port.c_str()));
this->thread_count = (s_threads == "" ? 5 : atoi (s_threads.c_str())) + 1; this->thread_count = (s_threads == "" ? 5 : atoi (s_threads.c_str())) + 1;
cout << "port=" << this->port << endl;
this->threads = new HANDLE[this->thread_count]; this->threads = new HANDLE[this->thread_count];
this->isRunning = false; this->isRunning = false;
@ -131,7 +130,7 @@ namespace UDPT
cout << "Thread (" << ( i + 1) << "/" << ((int)this->thread_count) << ") terminated." << endl; cout << "Thread (" << ( i + 1) << "/" << ((int)this->thread_count) << ") terminated." << endl;
} }
if (this->conn != NULL) if (this->conn != NULL)
db_close(this->conn); delete this->conn;
delete[] this->threads; delete[] this->threads;
} }
@ -148,11 +147,7 @@ namespace UDPT
if (sock == INVALID_SOCKET) if (sock == INVALID_SOCKET)
return START_ESOCKET_FAILED; return START_ESOCKET_FAILED;
#ifdef WIN32
recvAddr.sin_addr.S_un.S_addr = 0L;
#elif defined (linux)
recvAddr.sin_addr.s_addr = 0L; recvAddr.sin_addr.s_addr = 0L;
#endif
recvAddr.sin_family = AF_INET; recvAddr.sin_family = AF_INET;
recvAddr.sin_port = m_hton16 (this->port); recvAddr.sin_port = m_hton16 (this->port);
@ -173,11 +168,7 @@ namespace UDPT
this->sock = sock; this->sock = sock;
dbname = this->o_settings->get ("database", "file"); this->conn = new Data::SQLite3Driver (this->o_settings->getClass("database"), true);
if (dbname == "")
dbname = "tracker.db";
db_open(&this->conn, dbname.c_str());
this->isRunning = true; this->isRunning = true;
cout << "Starting maintenance thread (1/" << ((int)this->thread_count) << ")" << endl; cout << "Starting maintenance thread (1/" << ((int)this->thread_count) << ")" << endl;
@ -186,7 +177,7 @@ namespace UDPT
#ifdef WIN32 #ifdef WIN32
this->threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_maintainance_start, (LPVOID)this, 0, NULL); this->threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_maintainance_start, (LPVOID)this, 0, NULL);
#elif defined (linux) #elif defined (linux)
pthread_create (&usi->threads[0], NULL, _maintainance_start, usi); pthread_create (&usi->threads[0], NULL, _maintainance_start, (void*)this);
#endif #endif
for (i = 1;i < this->thread_count; i++) for (i = 1;i < this->thread_count; i++)
@ -195,26 +186,13 @@ namespace UDPT
#ifdef WIN32 #ifdef WIN32
this->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)this, 0, NULL); this->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)this, 0, NULL);
#elif defined (linux) #elif defined (linux)
pthread_create (&(this->threads[i]), NULL, _thread_start, this); pthread_create (&(this->threads[i]), NULL, _thread_start, (void*)this);
#endif #endif
} }
return START_OK; return START_OK;
} }
static uint64_t _get_connID (SOCKADDR_IN *remote)
{
int base;
uint64_t x;
base = time(NULL);
base /= 3600; // changes every hour.
x = base;
x += remote->sin_addr.s_addr;
return x;
}
int UDPTracker::sendError (UDPTracker *usi, SOCKADDR_IN *remote, uint32_t transactionID, const string &msg) int UDPTracker::sendError (UDPTracker *usi, SOCKADDR_IN *remote, uint32_t transactionID, const string &msg)
{ {
struct udp_error_response error; struct udp_error_response error;
@ -248,7 +226,13 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
resp.action = m_hton32(0); resp.action = m_hton32(0);
resp.transaction_id = req->transaction_id; resp.transaction_id = req->transaction_id;
resp.connection_id = _get_connID(remote);
if (!usi->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->sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
@ -262,16 +246,16 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
int q, // peer counts int q, // peer counts
bSize, // message size bSize, // message size
i; // loop index i; // loop index
db_peerEntry *peers; DatabaseDriver::PeerEntry *peers;
int32_t seeders, DatabaseDriver::TorrentEntry tE;
leechers,
completed;
db_peerEntry pE; // info for DB
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 (req->connection_id != _get_connID(remote)) if (!usi->conn->verifyConnectionId(req->connection_id,
m_hton32(remote->sin_addr.s_addr),
m_hton16(remote->sin_port)))
{ {
return 1; return 1;
} }
@ -291,25 +275,54 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
return 0; return 0;
} }
if (!usi->conn->isTorrentAllowed(req->info_hash))
{
UDPTracker::sendError(usi, remote, req->transaction_id, "info_hash not registered.");
return 0;
}
// load peers // load peers
q = 30; q = 30;
if (req->num_want >= 1) if (req->num_want >= 1)
q = min (q, req->num_want); q = min (q, req->num_want);
peers = (db_peerEntry*)malloc (sizeof(db_peerEntry) * q); peers = new DatabaseDriver::PeerEntry [q];
db_load_peers(usi->conn, req->info_hash, peers, &q);
DatabaseDriver::TrackerEvents event;
switch (req->event)
{
case 1:
event = DatabaseDriver::EVENT_COMPLETE;
break;
case 2:
event = DatabaseDriver::EVENT_START;
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->conn->getPeers(req->info_hash, &q, peers);
bSize = 20; // header is 20 bytes bSize = 20; // header is 20 bytes
bSize += (6 * q); // + 6 bytes per peer. bSize += (6 * q); // + 6 bytes per peer.
db_get_stats (usi->conn, req->info_hash, &seeders, &leechers, &completed); tE.info_hash = req->info_hash;
usi->conn->getTorrentInfo(&tE);
resp = (AnnounceResponse*)buff; resp = (AnnounceResponse*)buff;
resp->action = m_hton32(1); resp->action = m_hton32(1);
resp->interval = m_hton32 ( usi->announce_interval ); resp->interval = m_hton32 ( usi->announce_interval );
resp->leechers = m_hton32(leechers); resp->leechers = m_hton32(tE.leechers);
resp->seeders = m_hton32 (seeders); resp->seeders = m_hton32 (tE.seeders);
resp->transaction_id = req->transaction_id; resp->transaction_id = req->transaction_id;
for (i = 0;i < q;i++) for (i = 0;i < q;i++)
@ -328,24 +341,17 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
buff[25 + x] = (peers[i].port & 0xff); buff[25 + x] = (peers[i].port & 0xff);
} }
free (peers); delete[] peers;
sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN)); sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
// Add peer to list: // update DB.
pE.downloaded = req->downloaded; uint32_t ip;
pE.uploaded = req->uploaded;
pE.left = req->left;
pE.peer_id = req->peer_id;
if (req->ip_address == 0) // default if (req->ip_address == 0) // default
{ ip = m_hton32 (remote->sin_addr.s_addr);
pE.ip = m_hton32 (remote->sin_addr.s_addr);
}
else else
{ ip = req->ip_address;
pE.ip = req->ip_address; usi->conn->updatePeer(req->peer_id, req->info_hash, ip, req->port,
} req->downloaded, req->left, req->uploaded, event);
pE.port = req->port;
db_add_peer(usi->conn, req->info_hash, &pE);
return 0; return 0;
} }
@ -373,6 +379,13 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
return 0; return 0;
} }
if (!usi->conn->verifyConnectionId(sR->connection_id,
m_hton32(remote->sin_addr.s_addr),
m_hton16(remote->sin_port)))
{
return 1;
}
// get torrent count. // get torrent count.
c = v / 20; c = v / 20;
@ -382,7 +395,6 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
for (i = 0;i < c;i++) for (i = 0;i < c;i++)
{ {
int32_t s, c, l;
int32_t *seeders, int32_t *seeders,
*completed, *completed,
*leechers; *leechers;
@ -398,11 +410,17 @@ static uint64_t _get_connID (SOCKADDR_IN *remote)
completed = (int32_t*)&buffer[i*12+12]; completed = (int32_t*)&buffer[i*12+12];
leechers = (int32_t*)&buffer[i*12+16]; leechers = (int32_t*)&buffer[i*12+16];
db_get_stats (usi->conn, hash, &s, &l, &c); DatabaseDriver::TorrentEntry tE;
tE.info_hash = hash;
if (!usi->conn->getTorrentInfo(&tE))
{
sendError(usi, remote, sR->transaction_id, "Scrape Failed: couldn't retrieve torrent data");
return 0;
}
*seeders = m_hton32 (s); *seeders = m_hton32 (tE.seeders);
*completed = m_hton32 (c); *completed = m_hton32 (tE.completed);
*leechers = m_hton32 (l); *leechers = m_hton32 (tE.leechers);
} }
cout.flush(); cout.flush();
@ -436,7 +454,7 @@ static int _isIANA_IP (uint32_t ip)
} }
} }
cout << ":: " << (void*)remote->sin_addr.s_addr << ": " << remote->sin_port << " ACTION=" << action << endl; cout << ":: " << (void*)m_hton32(remote->sin_addr.s_addr) << ": " << m_hton16(remote->sin_port) << " ACTION=" << action << endl;
if (action == 0 && r >= 16) if (action == 0 && r >= 16)
return UDPTracker::handleConnection (usi, remote, data); return UDPTracker::handleConnection (usi, remote, data);
@ -499,10 +517,10 @@ static int _isIANA_IP (uint32_t ip)
while (usi->isRunning) while (usi->isRunning)
{ {
db_cleanup (usi->conn); usi->conn->cleanup();
#ifdef WIN32 #ifdef WIN32
Sleep (usi->cleanup_interval * 1000); // wait 2 minutes between every cleanup. Sleep (usi->cleanup_interval * 1000);
#elif defined (linux) #elif defined (linux)
sleep (usi->cleanup_interval); sleep (usi->cleanup_interval);
#else #else

View file

@ -23,7 +23,7 @@
#include <stdint.h> #include <stdint.h>
#include "multiplatform.h" #include "multiplatform.h"
#include "db/database.h" #include "db/driver_sqlite.hpp"
#include "settings.hpp" #include "settings.hpp"
#include <string> #include <string>
@ -142,7 +142,7 @@ namespace UDPT
uint8_t settings; uint8_t settings;
Settings *o_settings; Settings *o_settings;
dbConnection *conn; Data::DatabaseDriver *conn;
#ifdef WIN32 #ifdef WIN32
static DWORD _thread_start (LPVOID arg); static DWORD _thread_start (LPVOID arg);