Moving from C to C++... Some progress...
This commit is contained in:
parent
84ab27bfde
commit
51e2c80ba7
|
@ -22,6 +22,10 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct dbConnection dbConnection;
|
typedef struct dbConnection dbConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +34,7 @@ typedef struct dbConnection dbConnection;
|
||||||
* @param cStr Connection string for the active driver.
|
* @param cStr Connection string for the active driver.
|
||||||
* @return 0 on success; otherwise non-zero.
|
* @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.
|
* 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);
|
int db_remove_peer (dbConnection *db, uint8_t hash [20], db_peerEntry *pE);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif /* DATABASE_H_ */
|
#endif /* DATABASE_H_ */
|
||||||
|
|
|
@ -85,7 +85,7 @@ static void _db_setup (sqlite3 *db)
|
||||||
")", NULL, NULL, NULL);
|
")", NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_open (dbConnection **db, char *cStr)
|
int db_open (dbConnection **db, const char *cStr)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int doSetup, // check if to build DB, or it already exists?
|
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>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swaps Bytes:
|
* Swaps Bytes:
|
||||||
* example (htons):
|
* example (htons):
|
||||||
|
@ -39,4 +43,8 @@ uint64_t m_hton64 (uint64_t n);
|
||||||
|
|
||||||
void to_hex_str (const uint8_t *hash, char *data);
|
void to_hex_str (const uint8_t *hash, char *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* TOOLS_H_ */
|
#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