Moving from C to C++... Some progress...
This commit is contained in:
parent
84ab27bfde
commit
51e2c80ba7
|
@ -22,6 +22,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct dbConnection dbConnection;
|
||||
|
||||
/**
|
||||
|
@ -30,7 +34,7 @@ typedef struct dbConnection dbConnection;
|
|||
* @param cStr Connection string for the active driver.
|
||||
* @return 0 on success; otherwise non-zero.
|
||||
*/
|
||||
int db_open (dbConnection **pdb, char *cStr);
|
||||
int db_open (dbConnection **pdb, const char *cStr);
|
||||
|
||||
/**
|
||||
* Closes the database connection.
|
||||
|
@ -95,4 +99,7 @@ int db_cleanup (dbConnection *db);
|
|||
*/
|
||||
int db_remove_peer (dbConnection *db, uint8_t hash [20], db_peerEntry *pE);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* DATABASE_H_ */
|
||||
|
|
|
@ -85,7 +85,7 @@ static void _db_setup (sqlite3 *db)
|
|||
")", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int db_open (dbConnection **db, char *cStr)
|
||||
int db_open (dbConnection **db, const char *cStr)
|
||||
{
|
||||
FILE *f;
|
||||
int doSetup, // check if to build DB, or it already exists?
|
||||
|
|
114
src/main.c
114
src/main.c
|
@ -1,114 +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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "multiplatform.h"
|
||||
#include "udpTracker.h"
|
||||
#include "tools.h"
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "settings.h"
|
||||
|
||||
static void _print_usage ()
|
||||
{
|
||||
printf ("Usage: udpt [<configuration file>]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Settings settings;
|
||||
udpServerInstance usi;
|
||||
char *config_file;
|
||||
int r;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||
#endif
|
||||
|
||||
printf("UDP Tracker (UDPT) %s\nCopyright: (C) 2012 Naim Abda <naim94a@gmail.com>\n", VERSION);
|
||||
printf("Build Date: %s\n\n", __DATE__);
|
||||
|
||||
config_file = "udpt.conf";
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
_print_usage ();
|
||||
}
|
||||
|
||||
settings_init (&settings, config_file);
|
||||
if (settings_load (&settings) != 0)
|
||||
{
|
||||
const char strDATABASE[] = "database";
|
||||
const char strTRACKER[] = "tracker";
|
||||
// set default settings:
|
||||
|
||||
settings_set (&settings, strDATABASE, "driver", "sqlite3");
|
||||
settings_set (&settings, strDATABASE, "file", "tracker.db");
|
||||
|
||||
settings_set (&settings, strTRACKER, "port", "6969");
|
||||
settings_set (&settings, strTRACKER, "threads", "5");
|
||||
settings_set (&settings, strTRACKER, "allow_remotes", "yes");
|
||||
settings_set (&settings, strTRACKER, "allow_iana_ips", "yes");
|
||||
settings_set (&settings, strTRACKER, "announce_interval", "1800");
|
||||
settings_set (&settings, strTRACKER, "cleanup_interval", "120");
|
||||
|
||||
settings_save (&settings);
|
||||
printf("Failed to read from '%s'. Using default settings.\n", config_file);
|
||||
}
|
||||
|
||||
UDPTracker_init(&usi, &settings);
|
||||
|
||||
r = UDPTracker_start(&usi);
|
||||
if (r != 0)
|
||||
{
|
||||
printf("Error While trying to start server.\n");
|
||||
switch (r)
|
||||
{
|
||||
case 1:
|
||||
printf("Failed to create socket.\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("Failed to bind socket.\n");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown Error\n");
|
||||
break;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Press Any key to exit.\n");
|
||||
|
||||
getchar ();
|
||||
|
||||
cleanup:
|
||||
printf("\nGoodbye.\n");
|
||||
settings_destroy (&settings);
|
||||
UDPTracker_destroy(&usi);
|
||||
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
115
src/main.cpp
Normal file
115
src/main.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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 <iostream>
|
||||
|
||||
#include "multiplatform.h"
|
||||
#include "udpTracker.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace UDPT;
|
||||
|
||||
static void _print_usage ()
|
||||
{
|
||||
cout << "Usage: udpt [<configuration file>]" << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Settings *settings = NULL;
|
||||
UDPTracker *usi = NULL;
|
||||
string config_file;
|
||||
int r;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||
#endif
|
||||
|
||||
cout << "UDP Tracker (UDPT) " << VERSION << endl;
|
||||
cout << "Copyright 2012,2013 Naim Abda <naim94a@gmail.com>\n\tReleased under the GPLv3 License." << endl;
|
||||
cout << "Build Date: " << __DATE__ << endl << endl;
|
||||
|
||||
config_file = "udpt.conf";
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
_print_usage ();
|
||||
}
|
||||
|
||||
settings = new Settings (config_file);
|
||||
|
||||
if (!settings->load())
|
||||
{
|
||||
const char strDATABASE[] = "database";
|
||||
const char strTRACKER[] = "tracker";
|
||||
// set default settings:
|
||||
|
||||
settings->set (strDATABASE, "driver", "sqlite3");
|
||||
settings->set (strDATABASE, "file", "tracker.db");
|
||||
|
||||
settings->set (strTRACKER, "port", "6969");
|
||||
settings->set (strTRACKER, "threads", "5");
|
||||
settings->set (strTRACKER, "allow_remotes", "yes");
|
||||
settings->set (strTRACKER, "allow_iana_ips", "yes");
|
||||
settings->set (strTRACKER, "announce_interval", "1800");
|
||||
settings->set (strTRACKER, "cleanup_interval", "120");
|
||||
|
||||
settings->save();
|
||||
cout << "Failed to read from '" << config_file.c_str() << "'. Using default settings." << endl;
|
||||
}
|
||||
|
||||
usi = new UDPTracker (settings);
|
||||
|
||||
r = usi->start();
|
||||
if (r != UDPTracker::START_OK)
|
||||
{
|
||||
cout << "Error While trying to start server." << endl;
|
||||
switch (r)
|
||||
{
|
||||
case UDPTracker::START_ESOCKET_FAILED:
|
||||
cout << "Failed to create socket." << endl;
|
||||
break;
|
||||
case UDPTracker::START_EBIND_FAILED:
|
||||
cout << "Failed to bind socket." << endl;
|
||||
break;
|
||||
default:
|
||||
cout << "Unknown Error" << endl;
|
||||
break;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cout << "Press Any key to exit." << endl;
|
||||
|
||||
cin.get();
|
||||
|
||||
cleanup:
|
||||
cout << endl << "Goodbye." << endl;
|
||||
|
||||
delete usi;
|
||||
delete settings;
|
||||
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
373
src/settings.c
373
src/settings.c
|
@ -1,373 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
* UDPT is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* UDPT is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
SettingClass* settings_get_class (Settings *s, const char *classname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s == NULL || classname == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0;i < s->class_count;i++)
|
||||
{
|
||||
if (strcmp(classname, s->classes[i].classname) == 0)
|
||||
{
|
||||
return &s->classes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void settings_init (Settings *s, const char *filename)
|
||||
{
|
||||
s->buffer = NULL;
|
||||
s->filename = (char*)filename;
|
||||
s->classes = NULL;
|
||||
s->class_count = s->class_size = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void _settings_clean_string (char **str)
|
||||
{
|
||||
int len,
|
||||
i,
|
||||
offset;
|
||||
|
||||
len = strlen(*str);
|
||||
|
||||
//strip leading whitespaces.
|
||||
offset = 0;
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
if (isspace(*str[i]) == 0)
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
|
||||
(*str) += offset;
|
||||
len -= offset;
|
||||
|
||||
for (i = len - 1;i >= 0;i--)
|
||||
{
|
||||
if (isspace( (*str)[i] ) != 0)
|
||||
{
|
||||
(*str)[i] = '\0';
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void _settings_parser (Settings *s, char *data, int len)
|
||||
{
|
||||
char *className, *key, *value;
|
||||
int i,
|
||||
cil; // cil = Chars in line.
|
||||
char c;
|
||||
|
||||
className = key = value = NULL;
|
||||
cil = 0;
|
||||
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
c = data[i];
|
||||
if (c == '\n')
|
||||
{
|
||||
cil = 0;
|
||||
continue;
|
||||
}
|
||||
if (cil == 0 && c == ';')
|
||||
{
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isspace(c) != 0 && cil == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (cil == 0 && c == '[')
|
||||
{
|
||||
className = (char*)(i + data + 1);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] != ']')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
data[i] = '\0';
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isgraph(c) != 0 && cil == 0) // must be a key.
|
||||
{
|
||||
key = (char*)(i + data);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
key = NULL;
|
||||
break;
|
||||
}
|
||||
if (data[i] == '=')
|
||||
{
|
||||
data[i] = '\0';
|
||||
value = (char*)(data + i + 1);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
data[i] = '\0';
|
||||
|
||||
_settings_clean_string(&key);
|
||||
_settings_clean_string(&value);
|
||||
|
||||
// printf("KEY: '%s'\tVALUE: '%s'\n", key, value);
|
||||
|
||||
// add to settings...
|
||||
settings_set(s, className, key, value);
|
||||
|
||||
cil = 0;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isgraph(c) != 0)
|
||||
{
|
||||
cil++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int settings_load (Settings *s)
|
||||
{
|
||||
FILE *f;
|
||||
int len,
|
||||
r,
|
||||
offset; // file length
|
||||
char *buffer;
|
||||
char tmp [512];
|
||||
|
||||
if (s->buffer != NULL)
|
||||
{
|
||||
free (s->buffer);
|
||||
s->buffer = NULL;
|
||||
}
|
||||
|
||||
// ini file format.
|
||||
f = fopen(s->filename, "rb");
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
fseek (f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
s->buffer = (char*)malloc (len);
|
||||
buffer = s->buffer;
|
||||
|
||||
r = offset = 0;
|
||||
while (!feof(f) && !ferror(f))
|
||||
{
|
||||
int i;
|
||||
r = fread (tmp, 1, 512, f);
|
||||
for (i = 0;i < r;i++)
|
||||
{
|
||||
buffer[offset + i] = tmp[i];
|
||||
}
|
||||
offset += r;
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
// printf("File loaded into buffer. size=%d\n", len);
|
||||
_settings_parser (s, buffer, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settings_save (Settings *s)
|
||||
{
|
||||
char buffer [2048];
|
||||
SettingClass *sclass;
|
||||
FILE *f;
|
||||
int c, e;
|
||||
|
||||
f = fopen(s->filename, "wb");
|
||||
fprintf(f, "; udpt Settings File - Created Automatically.\n");
|
||||
setbuf(f, buffer);
|
||||
|
||||
for (c = 0;c < s->class_count;c++)
|
||||
{
|
||||
sclass = &s->classes[c];
|
||||
fprintf(f, "[%s]\n", sclass->classname);
|
||||
|
||||
for (e = 0;e < sclass->entry_count;e++)
|
||||
{
|
||||
fprintf(f, "%s=%s\n", sclass->entries[e].key, sclass->entries[e].values);
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void settings_destroy (Settings *s)
|
||||
{
|
||||
if (s->classes != NULL)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;i < s->class_count;i++)
|
||||
{
|
||||
if (s->classes[i].entries != NULL)
|
||||
free (s->classes[i].entries);
|
||||
}
|
||||
|
||||
free (s->classes);
|
||||
}
|
||||
if (s->buffer != NULL)
|
||||
{
|
||||
free (s->buffer);
|
||||
s->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char* settings_get (Settings *s, const char *class, const char *name)
|
||||
{
|
||||
SettingClass *c;
|
||||
|
||||
if (s == NULL || class == NULL || name == NULL)
|
||||
return NULL;
|
||||
|
||||
c = settings_get_class (s, class);
|
||||
return settingclass_get (c, name);
|
||||
}
|
||||
|
||||
int settings_set (Settings *s, const char *class, const char *name, const char *value)
|
||||
{
|
||||
SettingClass *c;
|
||||
|
||||
if (s == NULL || class == NULL || name == NULL)
|
||||
return 1;
|
||||
|
||||
c = settings_get_class (s, class);
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
if (s->class_count + 1 >= s->class_size)
|
||||
{
|
||||
int ns = s->class_size + 1;
|
||||
SettingClass *sc = realloc (s->classes, sizeof(SettingClass) * ns);
|
||||
if (sc == NULL)
|
||||
return 1;
|
||||
s->classes = sc;
|
||||
s->class_size = ns;
|
||||
}
|
||||
|
||||
c = &s->classes[s->class_count];
|
||||
s->class_count++;
|
||||
|
||||
c->classname = (char*)class;
|
||||
c->entries = NULL;
|
||||
c->entry_size = c->entry_count = 0;
|
||||
|
||||
}
|
||||
|
||||
return settingclass_set (c, name, value);
|
||||
}
|
||||
|
||||
char* settingclass_get (SettingClass *c, const char *name)
|
||||
{
|
||||
KeyValue *kv;
|
||||
int i;
|
||||
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0;i < c->entry_count;i++)
|
||||
{
|
||||
kv = &c->entries[i];
|
||||
if (strcmp(kv->key, name) == 0)
|
||||
return kv->values;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int settingclass_set (SettingClass *c, const char *name, const char *value)
|
||||
{
|
||||
|
||||
int i,
|
||||
ni;
|
||||
|
||||
for (i = 0;i < c->entry_count;i++)
|
||||
{
|
||||
if (strcmp(name, c->entries[i].key) == 0)
|
||||
{
|
||||
c->entries[i].values = (char*)value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->entry_count + 1 >= c->entry_size)
|
||||
{
|
||||
int ns;
|
||||
KeyValue *n;
|
||||
|
||||
ns = c->entry_size + 5;
|
||||
n = realloc (c->entries, sizeof(KeyValue) * ns);
|
||||
|
||||
if (n == NULL)
|
||||
return 1;
|
||||
|
||||
c->entries = n;
|
||||
c->entry_size = ns;
|
||||
}
|
||||
|
||||
ni = c->entry_count;
|
||||
c->entry_count++;
|
||||
|
||||
c->entries[ni].key = (char*)name;
|
||||
c->entries[ni].values = (char*)value;
|
||||
|
||||
return 0;
|
||||
}
|
294
src/settings.cpp
Normal file
294
src/settings.cpp
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
* UDPT is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* UDPT is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "settings.hpp"
|
||||
#include <string.h> // still primitive - need for strlen()
|
||||
#include <ctype.h> // need for isspace()
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
Settings::SettingClass* Settings::getClass(const string classname)
|
||||
{
|
||||
if (classname == "")
|
||||
return NULL;
|
||||
|
||||
map<string, SettingClass*>::iterator it;
|
||||
it = this->classes.find(classname);
|
||||
|
||||
if (it == this->classes.end())
|
||||
return NULL;
|
||||
else
|
||||
return it->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Settings::Settings (const string filename)
|
||||
{
|
||||
this->filename = filename;
|
||||
this->classes.clear();
|
||||
}
|
||||
|
||||
static
|
||||
void _settings_clean_string (char **str)
|
||||
{
|
||||
int len,
|
||||
i,
|
||||
offset;
|
||||
|
||||
len = strlen(*str);
|
||||
|
||||
//strip leading whitespaces.
|
||||
offset = 0;
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
if (isspace(*str[i]) == 0)
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
|
||||
(*str) += offset;
|
||||
len -= offset;
|
||||
|
||||
for (i = len - 1;i >= 0;i--)
|
||||
{
|
||||
if (isspace( (*str)[i] ) != 0)
|
||||
{
|
||||
(*str)[i] = '\0';
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::parseSettings (char *data, int len)
|
||||
{
|
||||
char *className, *key, *value;
|
||||
int i,
|
||||
cil; // cil = Chars in line.
|
||||
char c;
|
||||
|
||||
className = key = value = NULL;
|
||||
cil = 0;
|
||||
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
c = data[i];
|
||||
if (c == '\n')
|
||||
{
|
||||
cil = 0;
|
||||
continue;
|
||||
}
|
||||
if (cil == 0 && c == ';')
|
||||
{
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isspace(c) != 0 && cil == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (cil == 0 && c == '[')
|
||||
{
|
||||
className = (char*)(i + data + 1);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] != ']')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
data[i] = '\0';
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isgraph(c) != 0 && cil == 0) // must be a key.
|
||||
{
|
||||
key = (char*)(i + data);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
key = NULL;
|
||||
break;
|
||||
}
|
||||
if (data[i] == '=')
|
||||
{
|
||||
data[i] = '\0';
|
||||
value = (char*)(data + i + 1);
|
||||
while (i < len)
|
||||
{
|
||||
if (data[i] == '\n')
|
||||
{
|
||||
data[i] = '\0';
|
||||
|
||||
_settings_clean_string(&key);
|
||||
_settings_clean_string(&value);
|
||||
|
||||
// printf("KEY: '%s'\tVALUE: '%s'\n", key, value);
|
||||
|
||||
// add to settings...
|
||||
this->set (className, key, value);
|
||||
|
||||
cil = 0;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isgraph(c) != 0)
|
||||
{
|
||||
cil++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::load()
|
||||
{
|
||||
int len;
|
||||
char *buffer;
|
||||
|
||||
fstream cfg;
|
||||
cfg.open(this->filename.c_str(), ios::in | ios::binary);
|
||||
|
||||
if (!cfg.is_open())
|
||||
return false;
|
||||
|
||||
cfg.seekg(0, ios::end);
|
||||
len = cfg.tellg();
|
||||
cfg.seekg(0, ios::beg);
|
||||
|
||||
buffer = new char [len];
|
||||
cfg.read(buffer, len);
|
||||
cfg.close();
|
||||
|
||||
this->parseSettings(buffer, len);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Settings::save ()
|
||||
{
|
||||
SettingClass *sclass;
|
||||
|
||||
fstream cfg (this->filename.c_str(), ios::binary | ios::out);
|
||||
if (!cfg.is_open())
|
||||
return false;
|
||||
|
||||
cfg << "; udpt Settings File - Created Automatically.\n";
|
||||
|
||||
map<string, SettingClass*>::iterator it;
|
||||
for (it = this->classes.begin();it != this->classes.end();it++)
|
||||
{
|
||||
sclass = it->second;
|
||||
cfg << "[" << it->first.c_str() << "]\n";
|
||||
|
||||
map<string, string>::iterator rec;
|
||||
for (rec = sclass->entries.begin();rec != sclass->entries.end();rec++)
|
||||
{
|
||||
cfg << rec->first.c_str() << "=" << rec->second.c_str() << "\n";
|
||||
}
|
||||
|
||||
cfg << "\n";
|
||||
}
|
||||
cfg.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
map<string, SettingClass*>::iterator it;
|
||||
for (it = this->classes.begin();it != this->classes.end();it++)
|
||||
{
|
||||
SettingClass *sc = it->second;
|
||||
delete sc;
|
||||
}
|
||||
this->classes.clear();
|
||||
}
|
||||
|
||||
string Settings::get (const string classN, const string name)
|
||||
{
|
||||
SettingClass *c;
|
||||
|
||||
c = this->getClass(classN);
|
||||
return c->get(name);
|
||||
}
|
||||
|
||||
bool Settings::set (const string classN, const string name, const string value)
|
||||
{
|
||||
SettingClass *c;
|
||||
|
||||
if (classN == "" || name == "")
|
||||
return false;
|
||||
|
||||
c = this->getClass (classN);
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
c = new SettingClass(classN);
|
||||
this->classes.insert(pair<string, SettingClass*>(classN, c));
|
||||
}
|
||||
|
||||
return c->set (name, value);
|
||||
}
|
||||
|
||||
Settings::SettingClass::SettingClass(const string cn)
|
||||
{
|
||||
this->className = cn;
|
||||
}
|
||||
|
||||
string Settings::SettingClass::get (const string name)
|
||||
{
|
||||
return this->entries[name];
|
||||
}
|
||||
|
||||
bool Settings::SettingClass::set (const string name, const string value)
|
||||
{
|
||||
pair<map<string, string>::iterator, bool> r;
|
||||
r = this->entries.insert(pair<string, string>(name, value));
|
||||
if (!r.second)
|
||||
{
|
||||
r.first->second = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
101
src/settings.h
101
src/settings.h
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
* UDPT is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* UDPT is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
char *values;
|
||||
} KeyValue;
|
||||
|
||||
typedef struct {
|
||||
char *classname;
|
||||
KeyValue *entries;
|
||||
uint32_t entry_count, entry_size;
|
||||
} SettingClass;
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
|
||||
SettingClass *classes;
|
||||
uint32_t class_count, class_size;
|
||||
|
||||
char *buffer;
|
||||
} Settings;
|
||||
|
||||
/**
|
||||
* Initializes the settings type.
|
||||
* @param s Pointer to settings to initialize.
|
||||
* @param filename the settings filename.
|
||||
*/
|
||||
void settings_init (Settings *s, const char *filename);
|
||||
|
||||
/**
|
||||
* Loads settings from file
|
||||
* @param s pointer to settings type
|
||||
* @return 0 on success, otherwise non-zero.
|
||||
*/
|
||||
int settings_load (Settings *s);
|
||||
|
||||
/**
|
||||
* Saves settings to file.
|
||||
* @param s Pointer to settings.
|
||||
* @return 0 on success; otherwise non-zero.
|
||||
*/
|
||||
int settings_save (Settings *s);
|
||||
|
||||
/**
|
||||
* Destroys the settings "object"
|
||||
* @param s Pointer to settings.
|
||||
*/
|
||||
void settings_destroy (Settings *s);
|
||||
|
||||
/**
|
||||
* Gets the requested SettingClass.
|
||||
* @param s Settings Object.
|
||||
* @param classname The name of the class to find (case sensitive).
|
||||
* @return a pointer to the found class, or NULL if not found.
|
||||
*/
|
||||
SettingClass* settings_get_class (Settings *s, const char *classname);
|
||||
|
||||
char* settingclass_get (SettingClass *s, const char *name);
|
||||
|
||||
int settingclass_set (SettingClass *s, const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* Gets a setting from a Settings type.
|
||||
* @param s Pointer to a setting type.
|
||||
* @param class The class of the requested setting.
|
||||
* @param name The name of the requested setting.
|
||||
* @return The value for the requested setting, NULL if not available.
|
||||
*/
|
||||
char* settings_get (Settings *s, const char *classn, const char *name);
|
||||
|
||||
/**
|
||||
* Sets a setting in a settings type.
|
||||
* @param s Pointer to settings type.
|
||||
* @param class The class of the setting.
|
||||
* @param name The name of the setting.
|
||||
* @param value The value to set for the setting.
|
||||
* @return 0 on success, otherwise non-zero.
|
||||
*/
|
||||
int settings_set (Settings *s, const char *classn, const char *name, const char *value);
|
145
src/settings.hpp
Normal file
145
src/settings.hpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2012,2013 Naim A.
|
||||
*
|
||||
* This file is part of UDPT.
|
||||
*
|
||||
* UDPT is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* UDPT is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with UDPT. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
class Settings
|
||||
{
|
||||
public:
|
||||
class SettingClass
|
||||
{
|
||||
public:
|
||||
SettingClass (const string className);
|
||||
bool set (const string key, const string value);
|
||||
string get (const string key);
|
||||
private:
|
||||
friend class Settings;
|
||||
string className;
|
||||
map<string, string> entries;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the settings type.
|
||||
* @param filename the settings filename.
|
||||
*/
|
||||
Settings (const string filename);
|
||||
|
||||
/**
|
||||
* Gets a setting from a Settings type.
|
||||
* @param class The class of the requested setting.
|
||||
* @param name The name of the requested setting.
|
||||
* @return The value for the requested setting, NULL if not available.
|
||||
*/
|
||||
SettingClass* getClass (const string name);
|
||||
|
||||
/**
|
||||
* Loads settings from file
|
||||
* @return true on success, otherwise false.
|
||||
*/
|
||||
bool load ();
|
||||
|
||||
/**
|
||||
* Saves settings to file.
|
||||
* @return true on success; otherwise false.
|
||||
*/
|
||||
bool save ();
|
||||
|
||||
/**
|
||||
* Sets a setting in a settings type.
|
||||
* @param className The class of the setting.
|
||||
* @param key The name of the setting.
|
||||
* @param value The value to set for the setting.
|
||||
* @return true on success, otherwise false.
|
||||
*/
|
||||
bool set (const string className, const string key, const string value);
|
||||
|
||||
/**
|
||||
* Gets the requested SettingClass.
|
||||
* @param classname The name of the class to find (case sensitive).
|
||||
* @return a pointer to the found class, or NULL if not found.
|
||||
*/
|
||||
string get (const string className, const string key);
|
||||
|
||||
/**
|
||||
* Destroys the settings "object"
|
||||
*/
|
||||
virtual ~Settings ();
|
||||
private:
|
||||
string filename;
|
||||
map<string, SettingClass*> classes;
|
||||
|
||||
void parseSettings (char *data, int len);
|
||||
};
|
||||
};
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
//
|
||||
//typedef struct {
|
||||
// char *key;
|
||||
// char *values;
|
||||
//} KeyValue;
|
||||
//
|
||||
//typedef struct {
|
||||
// char *classname;
|
||||
// KeyValue *entries;
|
||||
// uint32_t entry_count, entry_size;
|
||||
//} SettingClass;
|
||||
//
|
||||
//typedef struct {
|
||||
// char *filename;
|
||||
//
|
||||
// SettingClass *classes;
|
||||
// uint32_t class_count, class_size;
|
||||
//
|
||||
// char *buffer;
|
||||
//} Settings;
|
||||
//
|
||||
//
|
||||
//void settings_init (Settings *s, const char *filename);
|
||||
//
|
||||
//int settings_load (Settings *s);
|
||||
//
|
||||
//int settings_save (Settings *s);
|
||||
//
|
||||
//void settings_destroy (Settings *s);
|
||||
//
|
||||
//SettingClass* settings_get_class (Settings *s, const char *classname);
|
||||
//
|
||||
//char* settingclass_get (SettingClass *s, const char *name);
|
||||
//
|
||||
//int settingclass_set (SettingClass *s, const char *name, const char *value);
|
||||
//
|
||||
//char* settings_get (Settings *s, const char *classn, const char *name);
|
||||
//
|
||||
//
|
||||
//int settings_set (Settings *s, const char *classn, const char *name, const char *value);
|
||||
//
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Swaps Bytes:
|
||||
* example (htons):
|
||||
|
@ -39,4 +43,8 @@ uint64_t m_hton64 (uint64_t n);
|
|||
|
||||
void to_hex_str (const uint8_t *hash, char *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TOOLS_H_ */
|
||||
|
|
520
src/udpTracker.c
520
src/udpTracker.c
|
@ -1,520 +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 "multiplatform.h"
|
||||
#include "udpTracker.h"
|
||||
#include "tools.h"
|
||||
#include "settings.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FLAG_RUNNING 0x01
|
||||
#define UDP_BUFFER_SIZE 2048
|
||||
|
||||
#ifdef WIN32
|
||||
static DWORD _thread_start (LPVOID arg);
|
||||
static DWORD _maintainance_start (LPVOID arg);
|
||||
#elif defined (linux)
|
||||
static void* _thread_start (void *arg);
|
||||
static void* _maintainance_start (void *arg);
|
||||
#endif
|
||||
|
||||
static int _isTrue (char *str)
|
||||
{
|
||||
int i, // loop index
|
||||
len; // string's length
|
||||
|
||||
if (str == NULL)
|
||||
return -1;
|
||||
len = strlen (str);
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
if (str[i] >= 'A' && str[i] <= 'Z')
|
||||
{
|
||||
str[i] = (str[i] - 'A' + 'a');
|
||||
}
|
||||
}
|
||||
if (strcmp(str, "yes") == 0)
|
||||
return 1;
|
||||
if (strcmp(str, "no") == 0)
|
||||
return 0;
|
||||
if (strcmp(str, "true") == 0)
|
||||
return 1;
|
||||
if (strcmp(str, "false") == 0)
|
||||
return 0;
|
||||
if (strcmp(str, "1") == 0)
|
||||
return 1;
|
||||
if (strcmp(str, "0") == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UDPTracker_init (udpServerInstance *usi, Settings *settings)
|
||||
{
|
||||
SettingClass *sc_tracker;
|
||||
uint8_t n_settings = 0;
|
||||
char *s_port, // port
|
||||
*s_threads, // threads
|
||||
*s_allow_remotes, // remotes allowed?
|
||||
*s_allow_iana_ip, // IANA IPs allowed?
|
||||
*s_int_announce, // announce interval
|
||||
*s_int_cleanup; // cleanup interval
|
||||
|
||||
sc_tracker = settings_get_class (settings, "tracker");
|
||||
|
||||
s_port = settingclass_get(sc_tracker, "port");
|
||||
s_threads = settingclass_get(sc_tracker, "threads");
|
||||
s_allow_remotes = settingclass_get (sc_tracker, "allow_remotes");
|
||||
s_allow_iana_ip = settingclass_get (sc_tracker, "allow_iana_ips");
|
||||
s_int_announce = settingclass_get (sc_tracker, "announce_interval");
|
||||
s_int_cleanup = settingclass_get (sc_tracker, "cleanup_interval");
|
||||
|
||||
if (_isTrue(s_allow_remotes) == 1)
|
||||
n_settings |= UDPT_ALLOW_REMOTE_IP;
|
||||
|
||||
if (_isTrue(s_allow_iana_ip) != 0)
|
||||
n_settings |= UDPT_ALLOW_IANA_IP;
|
||||
|
||||
usi->announce_interval = (s_int_announce == NULL ? 1800 : atoi (s_int_announce));
|
||||
usi->cleanup_interval = (s_int_cleanup == NULL ? 120 : atoi (s_int_cleanup));
|
||||
usi->port = (s_port == NULL ? 6969 : atoi (s_port));
|
||||
usi->thread_count = (s_threads == NULL ? 5 : atoi (s_threads)) + 1;
|
||||
|
||||
usi->threads = (HANDLE*)malloc (sizeof(HANDLE) * usi->thread_count);
|
||||
|
||||
usi->flags = 0;
|
||||
usi->conn = NULL;
|
||||
usi->settings = n_settings;
|
||||
usi->o_settings = settings;
|
||||
}
|
||||
|
||||
void UDPTracker_destroy (udpServerInstance *usi)
|
||||
{
|
||||
int i; // loop index
|
||||
|
||||
usi->flags &= ~FLAG_RUNNING;
|
||||
|
||||
// drop listener connection to continue thread loops.
|
||||
// wait for request to finish (1 second max; allot of time for a computer!).
|
||||
|
||||
#ifdef linux
|
||||
close (usi->sock);
|
||||
|
||||
sleep (1);
|
||||
#elif defined (WIN32)
|
||||
closesocket (usi->sock);
|
||||
|
||||
Sleep (1000);
|
||||
#endif
|
||||
|
||||
for (i = 0;i < usi->thread_count;i++)
|
||||
{
|
||||
#ifdef WIN32
|
||||
TerminateThread (usi->threads[0], 0x00);
|
||||
#elif defined (linux)
|
||||
pthread_detach (usi->threads[i]);
|
||||
pthread_cancel (usi->threads[i]);
|
||||
#endif
|
||||
printf ("Thread (%d/%u) terminated.\n", i + 1, usi->thread_count);
|
||||
}
|
||||
if (usi->conn != NULL)
|
||||
db_close(usi->conn);
|
||||
free (usi->threads);
|
||||
}
|
||||
|
||||
int UDPTracker_start (udpServerInstance *usi)
|
||||
{
|
||||
SOCKET sock;
|
||||
SOCKADDR_IN recvAddr;
|
||||
int r, // saves results
|
||||
i, // loop index
|
||||
yup; // just to set TRUE
|
||||
char *dbname;// saves the Database name.
|
||||
|
||||
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == INVALID_SOCKET)
|
||||
return 1;
|
||||
|
||||
#ifdef WIN32
|
||||
recvAddr.sin_addr.S_un.S_addr = 0L;
|
||||
#elif defined (linux)
|
||||
recvAddr.sin_addr.s_addr = 0L;
|
||||
#endif
|
||||
recvAddr.sin_family = AF_INET;
|
||||
recvAddr.sin_port = m_hton16 (usi->port);
|
||||
|
||||
yup = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yup, 1);
|
||||
|
||||
r = bind (sock, (SOCKADDR*)&recvAddr, sizeof(SOCKADDR_IN));
|
||||
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
#ifdef WIN32
|
||||
closesocket (sock);
|
||||
#elif defined (linux)
|
||||
close (sock);
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
usi->sock = sock;
|
||||
|
||||
dbname = settings_get (usi->o_settings, "database", "file");
|
||||
if (dbname == NULL)
|
||||
dbname = "tracker.db";
|
||||
|
||||
db_open(&usi->conn, dbname);
|
||||
|
||||
usi->flags |= FLAG_RUNNING;
|
||||
|
||||
// create maintainer thread.
|
||||
#ifdef WIN32
|
||||
usi->threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_maintainance_start, (LPVOID)usi, 0, NULL);
|
||||
#elif defined (linux)
|
||||
printf("Starting maintenance thread (1/%u)...\n", usi->thread_count);
|
||||
pthread_create (&usi->threads[0], NULL, _maintainance_start, usi);
|
||||
#endif
|
||||
|
||||
for (i = 1;i < usi->thread_count; i++)
|
||||
{
|
||||
printf("Starting Thread (%d/%u)\n", (i + 1), usi->thread_count);
|
||||
#ifdef WIN32
|
||||
usi->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)usi, 0, NULL);
|
||||
#elif defined (linux)
|
||||
pthread_create (&(usi->threads[i]), NULL, _thread_start, usi);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t _get_connID (SOCKADDR_IN *remote)
|
||||
{
|
||||
int base;
|
||||
uint64_t x;
|
||||
|
||||
base = time(NULL);
|
||||
base /= 3600; // changes every day.
|
||||
|
||||
x = base;
|
||||
x += remote->sin_addr.s_addr;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int _send_error (udpServerInstance *usi, SOCKADDR_IN *remote, uint32_t transactionID, char *msg)
|
||||
{
|
||||
struct udp_error_response error;
|
||||
int msg_sz, // message size to send.
|
||||
i; // copy loop
|
||||
char buff [1024]; // more than reasonable message size...
|
||||
|
||||
error.action = m_hton32 (3);
|
||||
error.transaction_id = transactionID;
|
||||
error.message = msg;
|
||||
|
||||
msg_sz = 4 + 4 + 1 + strlen(msg);
|
||||
|
||||
memcpy(buff, &error, 8);
|
||||
for (i = 8;i <= msg_sz;i++)
|
||||
{
|
||||
buff[i] = msg[i - 8];
|
||||
}
|
||||
|
||||
sendto(usi->sock, buff, msg_sz, 0, (SOCKADDR*)remote, sizeof(*remote));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_connection (udpServerInstance *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
ConnectionRequest *req;
|
||||
ConnectionResponse resp;
|
||||
|
||||
req = (ConnectionRequest*)data;
|
||||
|
||||
resp.action = m_hton32(0);
|
||||
resp.transaction_id = req->transaction_id;
|
||||
resp.connection_id = _get_connID(remote);
|
||||
|
||||
sendto(usi->sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_announce (udpServerInstance *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
AnnounceRequest *req;
|
||||
AnnounceResponse *resp;
|
||||
int q, // peer counts
|
||||
bSize, // message size
|
||||
i; // loop index
|
||||
db_peerEntry *peers;
|
||||
int32_t seeders,
|
||||
leechers,
|
||||
completed;
|
||||
db_peerEntry pE; // info for DB
|
||||
uint8_t buff [1028]; // Reasonable buffer size. (header+168 peers)
|
||||
|
||||
req = (AnnounceRequest*)data;
|
||||
|
||||
if (req->connection_id != _get_connID(remote))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// change byte order:
|
||||
req->port = m_hton16 (req->port);
|
||||
req->ip_address = m_hton32 (req->ip_address);
|
||||
req->downloaded = m_hton64 (req->downloaded);
|
||||
req->event = m_hton32 (req->event); // doesn't really matter for this tracker
|
||||
req->uploaded = m_hton64 (req->uploaded);
|
||||
req->num_want = m_hton32 (req->num_want);
|
||||
req->left = m_hton64 (req->left);
|
||||
|
||||
if ((usi->settings & UDPT_ALLOW_REMOTE_IP) == 0 && req->ip_address != 0)
|
||||
{
|
||||
_send_error (usi, remote, req->transaction_id, "Tracker doesn't allow remote IP's; Request ignored.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// load peers
|
||||
q = 30;
|
||||
if (req->num_want >= 1)
|
||||
q = min (q, req->num_want);
|
||||
|
||||
peers = (db_peerEntry*)malloc (sizeof(db_peerEntry) * q);
|
||||
|
||||
db_load_peers(usi->conn, req->info_hash, peers, &q);
|
||||
// printf("%d peers found.\n", q);
|
||||
|
||||
bSize = 20; // header is 20 bytes
|
||||
bSize += (6 * q); // + 6 bytes per peer.
|
||||
|
||||
db_get_stats (usi->conn, req->info_hash, &seeders, &leechers, &completed);
|
||||
|
||||
resp = (AnnounceResponse*)buff;
|
||||
resp->action = m_hton32(1);
|
||||
resp->interval = m_hton32 ( usi->announce_interval );
|
||||
resp->leechers = m_hton32(leechers);
|
||||
resp->seeders = m_hton32 (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);
|
||||
|
||||
}
|
||||
free (peers);
|
||||
sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
// Add peer to list:
|
||||
pE.downloaded = req->downloaded;
|
||||
pE.uploaded = req->uploaded;
|
||||
pE.left = req->left;
|
||||
pE.peer_id = req->peer_id;
|
||||
if (req->ip_address == 0) // default
|
||||
{
|
||||
pE.ip = m_hton32 (remote->sin_addr.s_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
pE.ip = req->ip_address;
|
||||
}
|
||||
pE.port = req->port;
|
||||
db_add_peer(usi->conn, req->info_hash, &pE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_scrape (udpServerInstance *usi, SOCKADDR_IN *remote, char *data, int len)
|
||||
{
|
||||
ScrapeRequest *sR;
|
||||
int v, // validation helper
|
||||
c, // torrent counter
|
||||
i, // loop counter
|
||||
j; // loop counter
|
||||
uint8_t hash [20];
|
||||
char xHash [50];
|
||||
ScrapeResponse *resp;
|
||||
uint8_t buffer [1024]; // up to 74 torrents can be scraped at once (17*74+8) < 1024
|
||||
|
||||
|
||||
sR = (ScrapeRequest*)data;
|
||||
|
||||
// validate request length:
|
||||
v = len - 16;
|
||||
if (v < 0 || v % 20 != 0)
|
||||
{
|
||||
_send_error (usi, remote, sR->transaction_id, "Bad scrape request.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get torrent count.
|
||||
c = v / 20;
|
||||
|
||||
resp = (ScrapeResponse*)buffer;
|
||||
resp->action = m_hton32 (2);
|
||||
resp->transaction_id = sR->transaction_id;
|
||||
|
||||
for (i = 0;i < c;i++)
|
||||
{
|
||||
int32_t s, c, l;
|
||||
int32_t *seeders,
|
||||
*completed,
|
||||
*leechers;
|
||||
|
||||
for (j = 0; j < 20;j++)
|
||||
hash[j] = data[j + (i*20)+16];
|
||||
|
||||
to_hex_str (hash, xHash);
|
||||
|
||||
printf("\t%s\n", xHash);
|
||||
|
||||
seeders = (int32_t*)&buffer[i*12+8];
|
||||
completed = (int32_t*)&buffer[i*12+12];
|
||||
leechers = (int32_t*)&buffer[i*12+16];
|
||||
|
||||
db_get_stats (usi->conn, hash, &s, &l, &c);
|
||||
|
||||
*seeders = m_hton32 (s);
|
||||
*completed = m_hton32 (c);
|
||||
*leechers = m_hton32 (l);
|
||||
}
|
||||
fflush (stdout);
|
||||
|
||||
sendto (usi->sock, (const char*)buffer, sizeof(buffer), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _isIANA_IP (uint32_t ip)
|
||||
{
|
||||
uint8_t x = (ip % 256);
|
||||
if (x == 0 || x == 10 || x == 127 || x >= 224)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _resolve_request (udpServerInstance *usi, SOCKADDR_IN *remote, char *data, int r)
|
||||
{
|
||||
ConnectionRequest *cR;
|
||||
uint32_t action;
|
||||
|
||||
cR = (ConnectionRequest*)data;
|
||||
|
||||
action = m_hton32(cR->action);
|
||||
|
||||
if ((usi->settings & UDPT_ALLOW_IANA_IP) > 0)
|
||||
{
|
||||
if (_isIANA_IP (remote->sin_addr.s_addr))
|
||||
{
|
||||
return 0; // Access Denied: IANA reserved IP.
|
||||
}
|
||||
}
|
||||
|
||||
printf(":: %x:%u ACTION=%d\n", (unsigned int)remote->sin_addr.s_addr , remote->sin_port, action);
|
||||
|
||||
if (action == 0 && r >= 16)
|
||||
return _handle_connection(usi, remote, data);
|
||||
else if (action == 1 && r >= 98)
|
||||
return _handle_announce(usi, remote, data);
|
||||
else if (action == 2)
|
||||
return _handle_scrape (usi, remote, data, r);
|
||||
else
|
||||
{
|
||||
printf("E: action=%d; r=%d\n", action, r);
|
||||
_send_error(usi, remote, cR->transaction_id, "Tracker couldn't understand Client's request.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static DWORD _thread_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
static void* _thread_start (void *arg)
|
||||
#endif
|
||||
{
|
||||
udpServerInstance *usi;
|
||||
SOCKADDR_IN remoteAddr;
|
||||
int addrSz,
|
||||
r;
|
||||
char tmpBuff [UDP_BUFFER_SIZE];
|
||||
|
||||
usi = arg;
|
||||
|
||||
addrSz = sizeof (SOCKADDR_IN);
|
||||
|
||||
|
||||
while ((usi->flags & FLAG_RUNNING) > 0)
|
||||
{
|
||||
fflush(stdout);
|
||||
// peek into the first 12 bytes of data; determine if connection request or announce request.
|
||||
r = recvfrom(usi->sock, tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, (unsigned*)&addrSz);
|
||||
if (r <= 0)
|
||||
continue; // bad request...
|
||||
r = _resolve_request(usi, &remoteAddr, tmpBuff, r);
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
pthread_exit (NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static DWORD _maintainance_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
static void* _maintainance_start (void *arg)
|
||||
#endif
|
||||
{
|
||||
udpServerInstance *usi;
|
||||
|
||||
usi = (udpServerInstance *)arg;
|
||||
|
||||
while ((usi->flags & FLAG_RUNNING) > 0)
|
||||
{
|
||||
db_cleanup (usi->conn);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep (usi->cleanup_interval * 1000); // wait 2 minutes between every cleanup.
|
||||
#elif defined (linux)
|
||||
sleep (usi->cleanup_interval);
|
||||
#else
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
516
src/udpTracker.cpp
Normal file
516
src/udpTracker.cpp
Normal file
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
* 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 "multiplatform.h"
|
||||
#include "udpTracker.hpp"
|
||||
#include "tools.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#define UDP_BUFFER_SIZE 2048
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
inline static int _isTrue (string str)
|
||||
{
|
||||
int i, // loop index
|
||||
len; // string's length
|
||||
|
||||
if (str == "")
|
||||
return -1;
|
||||
len = str.length();
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
if (str[i] >= 'A' && str[i] <= 'Z')
|
||||
{
|
||||
str[i] = (str[i] - 'A' + 'a');
|
||||
}
|
||||
}
|
||||
if (str.compare ("yes") == 0)
|
||||
return 1;
|
||||
if (str.compare ("no") == 0)
|
||||
return 0;
|
||||
if (str.compare("true") == 0)
|
||||
return 1;
|
||||
if (str.compare ("false") == 0)
|
||||
return 0;
|
||||
if (str.compare("1") == 0)
|
||||
return 1;
|
||||
if (str.compare ("0") == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
UDPTracker::UDPTracker (Settings *settings)
|
||||
{
|
||||
Settings::SettingClass *sc_tracker;
|
||||
uint8_t n_settings = 0;
|
||||
string s_port, // port
|
||||
s_threads, // threads
|
||||
s_allow_remotes, // remotes allowed?
|
||||
s_allow_iana_ip, // IANA IPs allowed?
|
||||
s_int_announce, // announce interval
|
||||
s_int_cleanup; // cleanup interval
|
||||
|
||||
sc_tracker = settings->getClass("tracker");
|
||||
|
||||
s_port = sc_tracker->get ("port");
|
||||
s_threads = sc_tracker->get ("threads");
|
||||
s_allow_remotes = sc_tracker->get ("allow_remotes");
|
||||
s_allow_iana_ip = sc_tracker->get ("allow_iana_ips");
|
||||
s_int_announce = sc_tracker->get ("announce_interval");
|
||||
s_int_cleanup = sc_tracker-> get ("cleanup_interval");
|
||||
|
||||
if (_isTrue(s_allow_remotes) == 1)
|
||||
n_settings |= UDPT_ALLOW_REMOTE_IP;
|
||||
|
||||
if (_isTrue(s_allow_iana_ip) != 0)
|
||||
n_settings |= UDPT_ALLOW_IANA_IP;
|
||||
|
||||
this->announce_interval = (s_int_announce == "" ? 1800 : atoi (s_int_announce.c_str()));
|
||||
this->cleanup_interval = (s_int_cleanup == "" ? 120 : atoi (s_int_cleanup.c_str()));
|
||||
this->port = (s_port == "" ? 6969 : atoi (s_port.c_str()));
|
||||
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->isRunning = false;
|
||||
this->conn = NULL;
|
||||
this->settings = n_settings;
|
||||
this->o_settings = settings;
|
||||
}
|
||||
|
||||
UDPTracker::~UDPTracker ()
|
||||
{
|
||||
int i; // loop index
|
||||
|
||||
this->isRunning = false;
|
||||
|
||||
// drop listener connection to continue thread loops.
|
||||
// wait for request to finish (1 second max; allot of time for a computer!).
|
||||
|
||||
#ifdef linux
|
||||
close (this->sock);
|
||||
|
||||
sleep (1);
|
||||
#elif defined (WIN32)
|
||||
closesocket (this->sock);
|
||||
|
||||
Sleep (1000);
|
||||
#endif
|
||||
|
||||
for (i = 0;i < this->thread_count;i++)
|
||||
{
|
||||
#ifdef WIN32
|
||||
TerminateThread (this->threads[i], 0x00);
|
||||
#elif defined (linux)
|
||||
pthread_detach (usi->threads[i]);
|
||||
pthread_cancel (usi->threads[i]);
|
||||
#endif
|
||||
cout << "Thread (" << ( i + 1) << "/" << ((int)this->thread_count) << ") terminated." << endl;
|
||||
}
|
||||
if (this->conn != NULL)
|
||||
db_close(this->conn);
|
||||
delete[] this->threads;
|
||||
}
|
||||
|
||||
enum UDPTracker::StartStatus UDPTracker::start ()
|
||||
{
|
||||
SOCKET sock;
|
||||
SOCKADDR_IN recvAddr;
|
||||
int r, // saves results
|
||||
i, // loop index
|
||||
yup; // just to set TRUE
|
||||
string dbname;// saves the Database name.
|
||||
|
||||
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == INVALID_SOCKET)
|
||||
return START_ESOCKET_FAILED;
|
||||
|
||||
#ifdef WIN32
|
||||
recvAddr.sin_addr.S_un.S_addr = 0L;
|
||||
#elif defined (linux)
|
||||
recvAddr.sin_addr.s_addr = 0L;
|
||||
#endif
|
||||
recvAddr.sin_family = AF_INET;
|
||||
recvAddr.sin_port = m_hton16 (this->port);
|
||||
|
||||
yup = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yup, 1);
|
||||
|
||||
r = bind (sock, (SOCKADDR*)&recvAddr, sizeof(SOCKADDR_IN));
|
||||
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
#ifdef WIN32
|
||||
closesocket (sock);
|
||||
#elif defined (linux)
|
||||
close (sock);
|
||||
#endif
|
||||
return START_EBIND_FAILED;
|
||||
}
|
||||
|
||||
this->sock = sock;
|
||||
|
||||
dbname = this->o_settings->get ("database", "file");
|
||||
if (dbname == "")
|
||||
dbname = "tracker.db";
|
||||
|
||||
db_open(&this->conn, dbname.c_str());
|
||||
|
||||
this->isRunning = true;
|
||||
cout << "Starting maintenance thread (1/" << ((int)this->thread_count) << ")" << endl;
|
||||
|
||||
// create maintainer thread.
|
||||
#ifdef WIN32
|
||||
this->threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_maintainance_start, (LPVOID)this, 0, NULL);
|
||||
#elif defined (linux)
|
||||
pthread_create (&usi->threads[0], NULL, _maintainance_start, usi);
|
||||
#endif
|
||||
|
||||
for (i = 1;i < this->thread_count; i++)
|
||||
{
|
||||
cout << "Starting thread (" << (i + 1) << "/" << ((int)this->thread_count) << ")" << endl;
|
||||
#ifdef WIN32
|
||||
this->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)this, 0, NULL);
|
||||
#elif defined (linux)
|
||||
pthread_create (&(this->threads[i]), NULL, _thread_start, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct udp_error_response error;
|
||||
int msg_sz, // message size to send.
|
||||
i; // copy loop
|
||||
char buff [1024]; // more than reasonable message size...
|
||||
|
||||
error.action = m_hton32 (3);
|
||||
error.transaction_id = transactionID;
|
||||
error.message = (char*)msg.c_str();
|
||||
|
||||
msg_sz = 4 + 4 + 1 + msg.length();
|
||||
|
||||
memcpy(buff, &error, 8);
|
||||
for (i = 8;i <= msg_sz;i++)
|
||||
{
|
||||
buff[i] = msg[i - 8];
|
||||
}
|
||||
|
||||
sendto(usi->sock, buff, msg_sz, 0, (SOCKADDR*)remote, sizeof(*remote));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::handleConnection (UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
ConnectionRequest *req;
|
||||
ConnectionResponse resp;
|
||||
|
||||
req = (ConnectionRequest*)data;
|
||||
|
||||
resp.action = m_hton32(0);
|
||||
resp.transaction_id = req->transaction_id;
|
||||
resp.connection_id = _get_connID(remote);
|
||||
|
||||
sendto(usi->sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::handleAnnounce (UDPTracker *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
AnnounceRequest *req;
|
||||
AnnounceResponse *resp;
|
||||
int q, // peer counts
|
||||
bSize, // message size
|
||||
i; // loop index
|
||||
db_peerEntry *peers;
|
||||
int32_t seeders,
|
||||
leechers,
|
||||
completed;
|
||||
db_peerEntry pE; // info for DB
|
||||
uint8_t buff [1028]; // Reasonable buffer size. (header+168 peers)
|
||||
|
||||
req = (AnnounceRequest*)data;
|
||||
|
||||
if (req->connection_id != _get_connID(remote))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// change byte order:
|
||||
req->port = m_hton16 (req->port);
|
||||
req->ip_address = m_hton32 (req->ip_address);
|
||||
req->downloaded = m_hton64 (req->downloaded);
|
||||
req->event = m_hton32 (req->event); // doesn't really matter for this tracker
|
||||
req->uploaded = m_hton64 (req->uploaded);
|
||||
req->num_want = m_hton32 (req->num_want);
|
||||
req->left = m_hton64 (req->left);
|
||||
|
||||
if ((usi->settings & UDPT_ALLOW_REMOTE_IP) == 0 && req->ip_address != 0)
|
||||
{
|
||||
UDPTracker::sendError (usi, remote, req->transaction_id, "Tracker doesn't allow remote IP's; Request ignored.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// load peers
|
||||
q = 30;
|
||||
if (req->num_want >= 1)
|
||||
q = min (q, req->num_want);
|
||||
|
||||
peers = (db_peerEntry*)malloc (sizeof(db_peerEntry) * q);
|
||||
|
||||
db_load_peers(usi->conn, req->info_hash, peers, &q);
|
||||
|
||||
bSize = 20; // header is 20 bytes
|
||||
bSize += (6 * q); // + 6 bytes per peer.
|
||||
|
||||
db_get_stats (usi->conn, req->info_hash, &seeders, &leechers, &completed);
|
||||
|
||||
resp = (AnnounceResponse*)buff;
|
||||
resp->action = m_hton32(1);
|
||||
resp->interval = m_hton32 ( usi->announce_interval );
|
||||
resp->leechers = m_hton32(leechers);
|
||||
resp->seeders = m_hton32 (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);
|
||||
|
||||
}
|
||||
free (peers);
|
||||
sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
// Add peer to list:
|
||||
pE.downloaded = req->downloaded;
|
||||
pE.uploaded = req->uploaded;
|
||||
pE.left = req->left;
|
||||
pE.peer_id = req->peer_id;
|
||||
if (req->ip_address == 0) // default
|
||||
{
|
||||
pE.ip = m_hton32 (remote->sin_addr.s_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
pE.ip = req->ip_address;
|
||||
}
|
||||
pE.port = req->port;
|
||||
db_add_peer(usi->conn, req->info_hash, &pE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::handleScrape (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len)
|
||||
{
|
||||
ScrapeRequest *sR;
|
||||
int v, // validation helper
|
||||
c, // torrent counter
|
||||
i, // loop counter
|
||||
j; // loop counter
|
||||
uint8_t hash [20];
|
||||
char xHash [50];
|
||||
ScrapeResponse *resp;
|
||||
uint8_t buffer [1024]; // up to 74 torrents can be scraped at once (17*74+8) < 1024
|
||||
|
||||
|
||||
sR = (ScrapeRequest*)data;
|
||||
|
||||
// validate request length:
|
||||
v = len - 16;
|
||||
if (v < 0 || v % 20 != 0)
|
||||
{
|
||||
UDPTracker::sendError (usi, remote, sR->transaction_id, "Bad scrape request.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get torrent count.
|
||||
c = v / 20;
|
||||
|
||||
resp = (ScrapeResponse*)buffer;
|
||||
resp->action = m_hton32 (2);
|
||||
resp->transaction_id = sR->transaction_id;
|
||||
|
||||
for (i = 0;i < c;i++)
|
||||
{
|
||||
int32_t s, c, l;
|
||||
int32_t *seeders,
|
||||
*completed,
|
||||
*leechers;
|
||||
|
||||
for (j = 0; j < 20;j++)
|
||||
hash[j] = data[j + (i*20)+16];
|
||||
|
||||
to_hex_str (hash, xHash);
|
||||
|
||||
cout << "\t" << xHash << endl;
|
||||
|
||||
seeders = (int32_t*)&buffer[i*12+8];
|
||||
completed = (int32_t*)&buffer[i*12+12];
|
||||
leechers = (int32_t*)&buffer[i*12+16];
|
||||
|
||||
db_get_stats (usi->conn, hash, &s, &l, &c);
|
||||
|
||||
*seeders = m_hton32 (s);
|
||||
*completed = m_hton32 (c);
|
||||
*leechers = m_hton32 (l);
|
||||
}
|
||||
cout.flush();
|
||||
|
||||
sendto (usi->sock, (const char*)buffer, sizeof(buffer), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _isIANA_IP (uint32_t ip)
|
||||
{
|
||||
uint8_t x = (ip % 256);
|
||||
if (x == 0 || x == 10 || x == 127 || x >= 224)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDPTracker::resolveRequest (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r)
|
||||
{
|
||||
ConnectionRequest *cR;
|
||||
uint32_t action;
|
||||
|
||||
cR = (ConnectionRequest*)data;
|
||||
|
||||
action = m_hton32(cR->action);
|
||||
|
||||
if ((usi->settings & UDPT_ALLOW_IANA_IP) == 0)
|
||||
{
|
||||
if (_isIANA_IP (remote->sin_addr.s_addr))
|
||||
{
|
||||
return 0; // Access Denied: IANA reserved IP.
|
||||
}
|
||||
}
|
||||
|
||||
cout << ":: " << (void*)remote->sin_addr.s_addr << ": " << remote->sin_port << " ACTION=" << action << endl;
|
||||
|
||||
if (action == 0 && r >= 16)
|
||||
return UDPTracker::handleConnection (usi, remote, data);
|
||||
else if (action == 1 && r >= 98)
|
||||
return UDPTracker::handleAnnounce (usi, remote, data);
|
||||
else if (action == 2)
|
||||
return UDPTracker::handleScrape (usi, remote, data, r);
|
||||
else
|
||||
{
|
||||
cout << "E: action=" << action << ", r=" << r << endl;
|
||||
UDPTracker::sendError (usi, remote, cR->transaction_id, "Tracker couldn't understand Client's request.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD UDPTracker::_thread_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
void* UDPTracker::_thread_start (void *arg)
|
||||
#endif
|
||||
{
|
||||
UDPTracker *usi;
|
||||
SOCKADDR_IN remoteAddr;
|
||||
int addrSz,
|
||||
r;
|
||||
char tmpBuff [UDP_BUFFER_SIZE];
|
||||
|
||||
usi = (UDPTracker*)arg;
|
||||
|
||||
addrSz = sizeof (SOCKADDR_IN);
|
||||
|
||||
|
||||
while (usi->isRunning)
|
||||
{
|
||||
cout.flush();
|
||||
// peek into the first 12 bytes of data; determine if connection request or announce request.
|
||||
r = recvfrom(usi->sock, (char*)tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
|
||||
if (r <= 0)
|
||||
continue; // bad request...
|
||||
r = UDPTracker::resolveRequest (usi, &remoteAddr, tmpBuff, r);
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
pthread_exit (NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD UDPTracker::_maintainance_start (LPVOID arg)
|
||||
#elif defined (linux)
|
||||
void* UDPTracker::_maintainance_start (void *arg)
|
||||
#endif
|
||||
{
|
||||
UDPTracker *usi;
|
||||
|
||||
usi = (UDPTracker *)arg;
|
||||
|
||||
while (usi->isRunning)
|
||||
{
|
||||
db_cleanup (usi->conn);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep (usi->cleanup_interval * 1000); // wait 2 minutes between every cleanup.
|
||||
#elif defined (linux)
|
||||
sleep (usi->cleanup_interval);
|
||||
#else
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
148
src/udpTracker.h
148
src/udpTracker.h
|
@ -1,148 +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 UDPTRACKER_H_
|
||||
#define UDPTRACKER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "multiplatform.h"
|
||||
#include "db/database.h"
|
||||
#include "settings.h"
|
||||
|
||||
struct udp_connection_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
};
|
||||
|
||||
struct udp_connection_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint64_t connection_id;
|
||||
};
|
||||
|
||||
struct udp_announce_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint8_t info_hash [20];
|
||||
uint8_t peer_id [20];
|
||||
uint64_t downloaded;
|
||||
uint64_t left;
|
||||
uint64_t uploaded;
|
||||
uint32_t event;
|
||||
uint32_t ip_address;
|
||||
uint32_t key;
|
||||
int32_t num_want;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
struct udp_announce_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint32_t interval;
|
||||
uint32_t leechers;
|
||||
uint32_t seeders;
|
||||
|
||||
uint8_t *peer_list_data;
|
||||
};
|
||||
|
||||
struct udp_scrape_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
|
||||
uint8_t *torrent_list_data;
|
||||
};
|
||||
|
||||
struct udp_scrape_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct udp_error_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
char *message;
|
||||
};
|
||||
|
||||
#define UDPT_DYNAMIC 0x01 // Track Any info_hash?
|
||||
#define UDPT_ALLOW_REMOTE_IP 0x02 // Allow client's to send other IPs?
|
||||
#define UDPT_ALLOW_IANA_IP 0x04 // allow IP's like 127.0.0.1 or other IANA reserved IPs?
|
||||
#define UDPT_VALIDATE_CLIENT 0x08 // validate client before adding to Database? (check if connection is open?)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET sock;
|
||||
uint16_t port;
|
||||
|
||||
uint8_t thread_count;
|
||||
|
||||
uint8_t flags;
|
||||
uint8_t settings;
|
||||
|
||||
HANDLE *threads;
|
||||
|
||||
uint32_t announce_interval;
|
||||
uint32_t cleanup_interval;
|
||||
|
||||
Settings *o_settings;
|
||||
dbConnection *conn;
|
||||
} udpServerInstance;
|
||||
|
||||
typedef struct udp_connection_request ConnectionRequest;
|
||||
typedef struct udp_connection_response ConnectionResponse;
|
||||
typedef struct udp_announce_request AnnounceRequest;
|
||||
typedef struct udp_announce_response AnnounceResponse;
|
||||
typedef struct udp_scrape_request ScrapeRequest;
|
||||
typedef struct udp_scrape_response ScrapeResponse;
|
||||
typedef struct udp_error_response ErrorResponse;
|
||||
|
||||
/**
|
||||
* Initializes the UDP Tracker.
|
||||
* @param usi The Instancfe to initialize.
|
||||
* @param port The port to bind the server to
|
||||
* @param threads Amount of threads to start the server with.
|
||||
*/
|
||||
void UDPTracker_init (udpServerInstance *usi, Settings *);
|
||||
|
||||
/**
|
||||
* Destroys resources that were created by UDPTracker_init.
|
||||
* @param usi Instance to destroy.
|
||||
*/
|
||||
void UDPTracker_destroy (udpServerInstance *usi);
|
||||
|
||||
/**
|
||||
* Starts the Initialized instance.
|
||||
* @param usi Instance to start
|
||||
* @return 0 on success, otherwise non-zero.
|
||||
*/
|
||||
int UDPTracker_start (udpServerInstance *usi);
|
||||
|
||||
#endif /* UDPTRACKER_H_ */
|
166
src/udpTracker.hpp
Normal file
166
src/udpTracker.hpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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 UDPTRACKER_H_
|
||||
#define UDPTRACKER_H_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "multiplatform.h"
|
||||
#include "db/database.h"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#define UDPT_DYNAMIC 0x01 // Track Any info_hash?
|
||||
#define UDPT_ALLOW_REMOTE_IP 0x02 // Allow client's to send other IPs?
|
||||
#define UDPT_ALLOW_IANA_IP 0x04 // allow IP's like 127.0.0.1 or other IANA reserved IPs?
|
||||
#define UDPT_VALIDATE_CLIENT 0x08 // validate client before adding to Database? (check if connection is open?)
|
||||
|
||||
|
||||
namespace UDPT
|
||||
{
|
||||
class UDPTracker
|
||||
{
|
||||
public:
|
||||
typedef struct udp_connection_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
} ConnectionRequest;
|
||||
|
||||
typedef struct udp_connection_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint64_t connection_id;
|
||||
} ConnectionResponse;
|
||||
|
||||
typedef struct udp_announce_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint8_t info_hash [20];
|
||||
uint8_t peer_id [20];
|
||||
uint64_t downloaded;
|
||||
uint64_t left;
|
||||
uint64_t uploaded;
|
||||
uint32_t event;
|
||||
uint32_t ip_address;
|
||||
uint32_t key;
|
||||
int32_t num_want;
|
||||
uint16_t port;
|
||||
} AnnounceRequest;
|
||||
|
||||
typedef struct udp_announce_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint32_t interval;
|
||||
uint32_t leechers;
|
||||
uint32_t seeders;
|
||||
|
||||
uint8_t *peer_list_data;
|
||||
} AnnounceResponse;
|
||||
|
||||
typedef struct udp_scrape_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
|
||||
uint8_t *torrent_list_data;
|
||||
} ScrapeRequest;
|
||||
|
||||
typedef struct udp_scrape_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
|
||||
uint8_t *data;
|
||||
} ScrapeResponse;
|
||||
|
||||
typedef struct udp_error_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
char *message;
|
||||
} ErrorResponse;
|
||||
|
||||
enum StartStatus
|
||||
{
|
||||
START_OK = 0,
|
||||
START_ESOCKET_FAILED = 1,
|
||||
START_EBIND_FAILED = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the UDP Tracker.
|
||||
* @param settings Settings to start server with
|
||||
*/
|
||||
UDPTracker (Settings *);
|
||||
|
||||
/**
|
||||
* Starts the Initialized instance.
|
||||
* @return 0 on success, otherwise non-zero.
|
||||
*/
|
||||
enum StartStatus start ();
|
||||
|
||||
/**
|
||||
* Destroys resources that were created by constructor
|
||||
* @param usi Instance to destroy.
|
||||
*/
|
||||
virtual ~UDPTracker ();
|
||||
|
||||
private:
|
||||
SOCKET sock;
|
||||
uint16_t port;
|
||||
uint8_t thread_count;
|
||||
bool isRunning;
|
||||
HANDLE *threads;
|
||||
uint32_t announce_interval;
|
||||
uint32_t cleanup_interval;
|
||||
|
||||
uint8_t settings;
|
||||
Settings *o_settings;
|
||||
dbConnection *conn;
|
||||
|
||||
#ifdef WIN32
|
||||
static DWORD _thread_start (LPVOID arg);
|
||||
static DWORD _maintainance_start (LPVOID arg);
|
||||
#elif defined (linux)
|
||||
static void* _thread_start (void *arg);
|
||||
static void* _maintainance_start (void *arg);
|
||||
#endif
|
||||
|
||||
static int resolveRequest (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int r);
|
||||
|
||||
static int handleConnection (UDPTracker *usi, SOCKADDR_IN *remote, char *data);
|
||||
static int handleAnnounce (UDPTracker *usi, SOCKADDR_IN *remote, char *data);
|
||||
static int handleScrape (UDPTracker *usi, SOCKADDR_IN *remote, char *data, int len);
|
||||
|
||||
static int sendError (UDPTracker *, SOCKADDR_IN *remote, uint32_t transId, const string &);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* UDPTRACKER_H_ */
|
Loading…
Reference in a new issue