Compare commits

...

33 Commits

Author SHA1 Message Date
Jan Vidar Krey
d98f013a51 Attempt to send messages via the Operations bot as private messages. 2013-02-14 02:36:37 +01:00
Jan Vidar Krey
2be48a13f7 Made sure we now have an 'Operations' user logged in.
This is still pretty much work in progress.
2013-02-14 00:16:18 +01:00
Jan Vidar Krey
70ba9d5831 Create a bot user system. 2013-02-13 21:10:13 +01:00
Jan Vidar Krey
f91f3ea68c Added funcions for sending notifications to operators.
Notifications could be compared to some sort of a log message,
but since it is broadcasted to operators live in the hub
it draws attention to them.
2013-02-13 21:10:30 +01:00
Jan Vidar Krey
5b78c0826d Added functions to route messages to operators only.
Technially the messages are routed to users with the
flag_opnotify set, but this is intended to be set only for
operators (and above) - and it allows operators to opt out
of these messages if they wish to.
2013-02-13 21:10:48 +01:00
Jan Vidar Krey
5c31f47bea Added methods for adding a string to be escaped automatically.
Previously only existed for named parameters.
2013-02-13 21:11:05 +01:00
Jan Vidar Krey
51a8e785c0 Attempt to address issues with timers overflowing (bug #198) 2013-02-13 21:11:22 +01:00
Jan Vidar Krey
8899e49f73 Added some auto-tests for bulk timeouts. 2013-02-13 21:11:39 +01:00
Jan Vidar Krey
d48ef710d8 Added an ADC hub redirector written in python. 2013-02-10 22:56:36 +01:00
Jan Vidar Krey
cfa210b3f3 Added a python version of the NMDC redirector. 2013-02-10 21:25:34 +01:00
Jan Vidar Krey
f6f7c7a3a4 Make sure we compile release builds with NDEBUG defined (to disable asserts). 2013-02-05 22:44:31 +01:00
Jan Vidar Krey
1fbde2b0fd Re-factored the ADC client code to use the new connection establishment API. 2013-02-05 22:43:59 +01:00
Jan Vidar Krey
92b65a0e14 Created a connection establishment API.
This API provides transparent asynchronous DNS lookups
with both IPv4 and IPv6 support, and in addition will try
to connect to all addresses until one of them work.

This implements the "happy eyeballs" algorithm provided that the client supports IPv6
and that the DNS records provides both IPv6 and IPv4 addresses.
2013-02-05 22:40:20 +01:00
Jan Vidar Krey
4d438e1e90 Don't poll the connection monitor if there are no connections added.
This caused the backends to return an error code, which
in turn ended the mainloop. However, several other things
also might occur in the main loop, such as DNS lookups which
come prior to creating any connections that in turn would be monitored.
2013-02-05 22:38:13 +01:00
Jan Vidar Krey
4f3c71234b Merge branch 'master' of https://github.com/3M3RY/uhub 2012-11-22 22:26:46 +01:00
Jan Vidar Krey
fdaadccb99 Merge pull request #18 from tehnick/fix-build-on-hurd-i386
(tehnick) Fix build in Debian GNU/Hurd.
2012-11-23 02:25:36 -08:00
Jan Vidar Krey
41251f8d32 Install uhub-passwd also. 2012-11-20 22:53:27 +01:00
Jan Vidar Krey
3b18ae251e Automatically find Sqlite3 - removed option to disable it.
This means Sqlite3 is now mandatory.
2012-11-20 22:53:27 +01:00
Boris Pek
b452488431 Fix build in Debian GNU/Hurd. 2012-11-20 22:41:38 +02:00
Emery
143b68588a Systemd notify support 2012-11-17 09:57:14 -06:00
Jan Vidar Krey
5f2b7bc069 Merge pull request #16 from 3M3RY/master
Systemd journaling support
2012-11-11 23:56:51 -08:00
Emery
ce68c446d1 Optional systemd journal logging 2012-11-11 15:21:00 -06:00
Jan Vidar Krey
6af0f293a6 Updated changelog for 0.4.1 release. 2012-11-07 20:24:06 +01:00
Jan Vidar Krey
a492f30950 Update authors file. 2012-11-07 20:08:28 +01:00
Jan Vidar Krey
a43953bc0d Added simple plugin that blocks downloads for non-registered users (guests). 2012-11-01 22:07:55 +01:00
Jan Vidar Krey
594801df46 Fix windows compile issues. 2012-11-01 21:52:33 +01:00
Jan Vidar Krey
3dcbb63a31 Implemented a simlpe red-black tree which should give better performance
for certain lookups.

The rb_tree will act as a general purpose key/value storage, and
also give a performance boost in the cases where the other
simple alternative would be to use a linked_list.

On average this should give on average O(log n) lookups, while the linked_list
would be O(n) at worst.
2012-11-01 21:46:44 +01:00
Jan Vidar Krey
5d6184961b Fix a failing test on Windows. 2012-11-01 21:18:49 +01:00
Jan Vidar Krey
b17e88573e Fixed Windows VC compile issues with autotests. 2012-11-01 21:10:51 +01:00
Jan Vidar Krey
2d2ccc0039 Merge branch 'async_dns_api' 2012-11-01 10:42:19 +01:00
Jan Vidar Krey
0a2f9c4b79 Merge branch 'autotest' 2012-11-01 10:40:51 +01:00
Jan Vidar Krey
ae62c35cb9 Disable SSL compression. 2012-11-01 10:39:31 +01:00
Jan Vidar Krey
2ec2e73f16 Make sure we always build the autotests.
Caveat, need to run the update script manually after changing the tests (adding or removing tests).
However, modifying existing tests does not require running the update script.

Added a copy of exotic in the repository

exotic automatically generates the skeleton code around the autotests in order to schedule
the tests.
2012-10-25 17:27:45 +02:00
42 changed files with 3144 additions and 268 deletions

View File

@@ -3,7 +3,9 @@ Authors of uhub
Jan Vidar Krey, Design and implementation
E_zombie, Centos/RedHat customization scripts and heavy load testing
FleetCommand, Hub topic
FleetCommand, Hub topic plugin code
MiMic, Implemented user commands
tehnick, Debian and Ubuntu packaging.
Boris Pek (tehnick), Debian/Ubuntu packaging
Tillmann Karras (Tilka), Misc. bug fixes
Yoran Heling (Yorhel), TLS/SSL handshake detection bugfixes
Blair Bonnett, Misc. bug fixes

View File

@@ -3,7 +3,7 @@
## Copyright (C) 2007-2012, Jan Vidar Krey <janvidar@extatic.org>
#
cmake_minimum_required (VERSION 2.8.3)
cmake_minimum_required (VERSION 2.8.2)
project (uhub NONE)
enable_language(C)
@@ -13,15 +13,17 @@ set (UHUB_VERSION_MINOR 4)
set (UHUB_VERSION_PATCH 1)
set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules)
option(RELEASE "Release build, debug build if disabled" ON)
option(LINK_SUPPORT "Allow hub linking" OFF)
option(SSL_SUPPORT "Enable SSL support" ON)
option(USE_OPENSSL "Use OpenSSL's SSL support" ON )
option(SQLITE_SUPPORT "Enable SQLite support" ON)
option(SYSTEMD_SUPPORT "Enable systemd notify and journal logging" OFF)
option(ADC_STRESS "Enable the stress tester client" OFF)
find_package(Git)
find_package(Sqlite3)
if (SSL_SUPPORT)
if (USE_OPENSSL)
@@ -34,11 +36,18 @@ if (SSL_SUPPORT)
endif()
endif()
if (SYSTEMD_SUPPORT)
INCLUDE(FindPkgConfig)
pkg_search_module(SD_DAEMON REQUIRED libsystemd-daemon)
pkg_search_module(SD_JOURNAL REQUIRED libsystemd-journal)
endif()
if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories("${PROJECT_SOURCE_DIR}")
include_directories(${SQLITE3_INCLUDE_DIRS})
file (GLOB uhub_SOURCES ${PROJECT_SOURCE_DIR}/core/*.c)
list (REMOVE_ITEM uhub_SOURCES
@@ -67,6 +76,8 @@ add_dependencies(adc utils)
add_dependencies(network utils)
add_executable(uhub ${PROJECT_SOURCE_DIR}/core/main.c ${uhub_SOURCES} )
add_executable(test ${CMAKE_SOURCE_DIR}/autotest/test.c ${uhub_SOURCES} )
add_executable(uhub-passwd ${PROJECT_SOURCE_DIR}/tools/uhub-passwd.c)
add_library(mod_example MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_example.c)
add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c)
@@ -75,19 +86,12 @@ add_library(mod_auth_simple MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_simple
add_library(mod_chat_history MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_chat_history.c )
add_library(mod_chat_only MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_chat_only.c)
add_library(mod_topic MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_topic.c)
if (SQLITE_SUPPORT)
add_library(mod_auth_sqlite MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_sqlite.c)
add_executable(uhub-passwd ${PROJECT_SOURCE_DIR}/tools/uhub-passwd.c)
target_link_libraries(mod_auth_sqlite sqlite3 utils)
target_link_libraries(uhub-passwd sqlite3 utils)
set_target_properties(mod_auth_sqlite PROPERTIES PREFIX "")
endif()
add_library(mod_no_guest_downloads MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_no_guest_downloads.c)
add_library(mod_auth_sqlite MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_sqlite.c)
if(WIN32)
target_link_libraries(uhub ws2_32)
target_link_libraries(test ws2_32)
target_link_libraries(mod_logging ws2_32)
target_link_libraries(mod_welcome ws2_32)
endif()
@@ -97,16 +101,22 @@ set_target_properties(
mod_welcome
mod_logging
mod_auth_simple
mod_auth_sqlite
mod_chat_history
mod_chat_only
mod_no_guest_downloads
mod_topic
PROPERTIES PREFIX "")
target_link_libraries(uhub ${CMAKE_DL_LIBS} adc network utils)
target_link_libraries(uhub-passwd ${SQLITE3_LIBRARIES} utils)
target_link_libraries(test ${CMAKE_DL_LIBS} adc network utils)
target_link_libraries(mod_example utils)
target_link_libraries(mod_welcome utils)
target_link_libraries(mod_auth_simple utils)
target_link_libraries(mod_auth_sqlite ${SQLITE3_LIBRARIES} utils)
target_link_libraries(mod_chat_history utils)
target_link_libraries(mod_no_guest_downloads utils)
target_link_libraries(mod_chat_only utils)
target_link_libraries(mod_logging utils)
target_link_libraries(mod_topic utils)
@@ -114,11 +124,13 @@ target_link_libraries(utils network)
target_link_libraries(mod_welcome network)
target_link_libraries(mod_logging network)
if(UNIX)
add_library(adcclient STATIC ${adcclient_SOURCES})
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c)
target_link_libraries(uhub-admin adcclient adc network utils pthread)
target_link_libraries(uhub pthread)
target_link_libraries(test pthread)
if (ADC_STRESS)
add_executable(adcrush ${PROJECT_SOURCE_DIR}/tools/adcrush.c ${adcclient_SOURCES})
@@ -157,6 +169,7 @@ endif()
if(SSL_SUPPORT)
target_link_libraries(uhub ${SSL_LIBS})
target_link_libraries(test ${SSL_LIBS})
if(UNIX)
target_link_libraries(uhub-admin ${SSL_LIBS})
endif()
@@ -167,24 +180,33 @@ if(SSL_SUPPORT)
endif()
endif()
if (SYSTEMD_SUPPORT)
target_link_libraries(uhub ${SD_DAEMON_LIBRARIES})
target_link_libraries(uhub ${SD_JOURNAL_LIBRARIES})
target_link_libraries(test ${SD_DAEMON_LIBRARIES})
target_link_libraries(test ${SD_JOURNAL_LIBRARIES})
target_link_libraries(uhub-passwd ${SD_JOURNAL_LIBRARIES})
target_link_libraries(uhub-admin ${SD_JOURNAL_LIBRARIES})
include_directories(${SD_DAEMON_INCLUDE_DIRS})
include_directories(${SD_JOURNAL_INCLUDE_DIRS})
add_definitions(-DSYSTEMD)
endif()
configure_file ("${PROJECT_SOURCE_DIR}/version.h.in" "${PROJECT_SOURCE_DIR}/version.h")
mark_as_advanced(FORCE CMAKE_BUILD_TYPE)
if (RELEASE)
set(CMAKE_BUILD_TYPE Release)
add_definitions(-DNDEBUG)
else()
set(CMAKE_BUILD_TYPE Debug)
# add_definitions(-DDEBUG)
endif()
if (UNIX)
install( TARGETS uhub RUNTIME DESTINATION bin )
install( TARGETS mod_example mod_welcome mod_logging mod_auth_simple mod_auth_sqlite mod_chat_history mod_chat_only mod_topic DESTINATION /usr/lib/uhub/ OPTIONAL )
install( TARGETS uhub uhub-passwd RUNTIME DESTINATION bin )
install( TARGETS mod_example mod_welcome mod_logging mod_auth_simple mod_auth_sqlite mod_chat_history mod_chat_only mod_topic mod_no_guest_downloads DESTINATION /usr/lib/uhub/ OPTIONAL )
install( FILES ${CMAKE_SOURCE_DIR}/doc/uhub.conf ${CMAKE_SOURCE_DIR}/doc/plugins.conf ${CMAKE_SOURCE_DIR}/doc/rules.txt ${CMAKE_SOURCE_DIR}/doc/motd.txt DESTINATION /etc/uhub OPTIONAL )
if (SQLITE_SUPPORT)
install( TARGETS uhub-passwd RUNTIME DESTINATION bin )
endif()
endif()

View File

@@ -1,3 +1,18 @@
0.4.1:
- Converted to CMake which replaces Visual Studio project files and GNU makefiles
- Fix issues with SSL causing excessive CPU usage.
- Fix TLS/SSL handshake detection issues
- Fixed crash in mod_chat_only.
- Implemented red-black tree for better performance for certain lookups.
- Better network statistics using the !stats command.
- Improved protocol parsing, especially escape handling.
- Fix cbuffer initialization.
- Install plugins in /usr/lib/uhub, not /var/lib/uhub.
- Improved init scripts and added a upstart script.
- Work-around client security bugs by disallowing UCMD messages from being relayed.
- Added asynchronous DNS resolver.
0.4.0:
- Cleaned up code generator for config file parsing.
- Merge pull request #5 from yorhel/master

372
autotest/exotic Executable file
View File

@@ -0,0 +1,372 @@
#!/usr/bin/perl -w
# exotic 0.4
# Copyright (c) 2007-2012, Jan Vidar Krey
use strict;
my $program = $0;
my $file;
my $line;
my @tests;
my $found;
my $test;
my @files;
if ($#ARGV == -1)
{
die "Usage: $program files\n";
}
my $version = "0.4";
foreach my $arg (@ARGV)
{
push(@files, $arg);
}
print "/* THIS FILE IS AUTOMATICALLY GENERATED BY EXOTIC - DO NOT EDIT THIS FILE! */\n";
print "/* exotic/$version (Mon Nov 7 11:15:31 CET 2011) */\n\n";
print "#define __EXOTIC__STANDALONE__\n";
standalone_include_exotic_h();
if ($#ARGV >= 0)
{
foreach $file (@ARGV)
{
$found = 0;
open( FILE, "$file") || next;
my @data = <FILE>;
my $comment = 0;
foreach $line (@data) {
chomp($line);
if ($comment == 1)
{
if ($line =~ /^(.*\*\/)(.*)/)
{
$line = $2;
$comment = 0;
}
else
{
next; # ignore comment data
}
}
if ($line =~ /^(.*)\/\*(.*)\*\/(.*)$/)
{
$line = $1 . " " . $3; # exclude comment stuff in between "/*" and "*/".
}
if ($line =~ /^(.*)(\/\/.*)$/) {
$line = $1; # exclude stuff after "//" (FIXME: does not work if they are inside a string)
}
if ($line =~ /\/\*/) {
$comment = 1;
next;
}
if ($line =~ /^\s*EXO_TEST\(\s*(\w+)\s*,/)
{
$found++;
push(@tests, $1);
}
}
if ($found > 0) {
print "#include \"" . $file . "\"\n";
}
close(FILE);
}
print "\n";
}
# Write a main() that will start the test run
print "int main(int argc, char** argv)\n{\n";
print "\tstruct exotic_handle handle;\n\n";
print "\tif (exotic_initialize(&handle, argc, argv) == -1)\n\t\treturn -1;\n\n";
if ($#tests > 0)
{
print "\t/* Register the tests to be run */\n";
foreach $test (@tests)
{
print "\texotic_add_test(&handle, &exotic_test_" . $test . ", \"" . $test . "\");\n";
}
}
else
{
print "\t/* No tests are found! */\n";
}
print "\n";
print "\treturn exotic_run(&handle);\n";
print "}\n\n";
standalone_include_exotic_c();
sub standalone_include_exotic_h {
print '
/*
* Exotic (EXtatic.Org Test InfrastuCture)
* Copyright (c) 2007, Jan Vidar Krey
*/
#ifndef EXO_TEST
#define EXO_TEST(NAME, block) int exotic_test_ ## NAME (void) block
#endif
#ifndef HAVE_EXOTIC_AUTOTEST_H
#define HAVE_EXOTIC_AUTOTEST_H
#ifdef __cplusplus
extern "C" {
#endif
typedef int(*exo_test_t)();
enum exo_toggle { cfg_default, cfg_off, cfg_on };
struct exotic_handle
{
enum exo_toggle config_show_summary;
enum exo_toggle config_show_pass;
enum exo_toggle config_show_fail;
unsigned int fail;
unsigned int pass;
struct exo_test_data* first;
struct exo_test_data* current;
};
extern int exotic_initialize(struct exotic_handle* handle, int argc, char** argv);
extern void exotic_add_test(struct exotic_handle* handle, exo_test_t, const char* name);
extern int exotic_run(struct exotic_handle* handle);
#ifdef __cplusplus
}
#endif
#endif /* HAVE_EXOTIC_AUTOTEST_H */
'; }
sub standalone_include_exotic_c {
print '
/*
* Exotic - C/C++ source code testing
* Copyright (c) 2007, Jan Vidar Krey
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void exotic_version();
#ifndef __EXOTIC__STANDALONE__
#include "autotest.h"
static void exotic_version()
{
printf("Extatic.org Test Infrastructure: exotic " "${version}" "\n\n");
printf("Copyright (C) 2007 Jan Vidar Krey, janvidar@extatic.org\n");
printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n");
}
#endif
struct exo_test_data
{
exo_test_t test;
char* name;
struct exo_test_data* next;
};
static void exotic_summary(struct exotic_handle* handle)
{
int total = handle->pass + handle->fail;
int pass_rate = total ? (100*handle->pass / total) : 0;
int fail_rate = total ? (100*handle->fail / total) : 0;
printf("\n");
printf("--------------------------------------------\n");
printf("Results:\n");
printf(" * Total tests run: %8d\n", total);
printf(" * Tests passed: %8d (~%d%%)\n", (int) handle->pass, pass_rate);
printf(" * Tests failed: %8d (~%d%%)\n", (int) handle->fail, fail_rate);
printf("--------------------------------------------\n");
}
static void exotic_help(const char* program)
{
printf("Usage: %s [OPTIONS]\n\n", program);
printf("Options:\n");
printf(" --help -h Show this message\n");
printf(" --version -v Show version\n");
printf(" --summary -s show only summary)\n");
printf(" --fail -f show only test failures\n");
printf(" --pass -p show only test passes\n");
printf("\nExamples:\n");
printf(" %s -s -f\n\n", program);
}
int exotic_initialize(struct exotic_handle* handle, int argc, char** argv)
{
int n;
if (!handle || !argv) return -1;
memset(handle, 0, sizeof(struct exotic_handle));
for (n = 1; n < argc; n++)
{
if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help"))
{
exotic_help(argv[0]);
exit(0);
}
if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--version"))
{
exotic_version();
exit(0);
}
if (!strcmp(argv[n], "-s") || !strcmp(argv[n], "--summary"))
{
handle->config_show_summary = cfg_on;
continue;
}
if (!strcmp(argv[n], "-f") || !strcmp(argv[n], "--fail"))
{
handle->config_show_fail = cfg_on;
continue;
}
if (!strcmp(argv[n], "-p") || !strcmp(argv[n], "--pass"))
{
handle->config_show_pass = cfg_on;
continue;
}
fprintf(stderr, "Unknown argument: %s\n\n", argv[n]);
exotic_help(argv[0]);
exit(0);
}
if (handle->config_show_summary == cfg_on)
{
if (handle->config_show_pass == cfg_default) handle->config_show_pass = cfg_off;
if (handle->config_show_fail == cfg_default) handle->config_show_fail = cfg_off;
}
else if (handle->config_show_pass == cfg_on)
{
if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_off;
if (handle->config_show_fail == cfg_default) handle->config_show_fail = cfg_off;
}
else if (handle->config_show_fail == cfg_on)
{
if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_off;
if (handle->config_show_fail == cfg_default) handle->config_show_fail = cfg_off;
}
else
{
if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_on;
if (handle->config_show_fail == cfg_default) handle->config_show_fail = cfg_on;
if (handle->config_show_pass == cfg_default) handle->config_show_pass = cfg_on;
}
return 0;
}
void exotic_add_test(struct exotic_handle* handle, exo_test_t func, const char* name)
{
struct exo_test_data* test;
if (!handle)
{
fprintf(stderr, "exotic_add_test: failed, no handle!\n");
exit(-1);
}
test = (struct exo_test_data*) malloc(sizeof(struct exo_test_data));
if (!test)
{
fprintf(stderr, "exotic_add_test: out of memory!\n");
exit(-1);
}
/* Create the test */
memset(test, 0, sizeof(struct exo_test_data));
test->test = func;
test->name = strdup(name);
/* Register the test in the handle */
if (!handle->first)
{
handle->first = test;
handle->current = test;
}
else
{
handle->current->next = test;
handle->current = test;
}
}
int exotic_run(struct exotic_handle* handle)
{
struct exo_test_data* tmp = NULL;
if (!handle)
{
fprintf(stderr, "Error: exotic is not initialized\n");
return -1;
}
handle->current = handle->first;
while (handle->current)
{
tmp = handle->current;
if (handle->current->test()) {
if (handle->config_show_pass == cfg_on) printf("* PASS test \'%s\'\n", tmp->name);
handle->pass++;
} else {
if (handle->config_show_fail == cfg_on) printf("* FAIL test \'%s\'\n", tmp->name);
handle->fail++;
}
handle->current = handle->current->next;
free(tmp->name);
free(tmp);
}
if (!handle->first)
{
printf("(No tests added)\n");
}
if (handle->config_show_summary == cfg_on)
exotic_summary(handle);
return (handle->fail) ? handle->fail : 0;
}
static void exotic_version() {
printf("exotic 0.4-standalone\n\n");
printf("Copyright (C) 2007 Jan Vidar Krey, janvidar@extatic.org\n");
printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n");
}
'; }

1034
autotest/test.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@ extern int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, st
static void inf_create_hub()
{
net_initialize();
inf_hub = (struct hub_info*) hub_malloc_zero(sizeof(struct hub_info));
inf_hub->users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
inf_hub->users->list = list_create();
@@ -35,6 +36,7 @@ static void inf_destroy_hub()
hub_free(inf_hub->acl);
hub_free(inf_hub->config);
hub_free(inf_hub);
net_destroy();
}
@@ -63,13 +65,14 @@ EXO_TEST(inf_create_setup,
/* FIXME: MEMORY LEAK - Need to fix hub_handle_info_login */
#define CHECK_INF(MSG, EXPECT) \
do { \
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
adc_msg_free(msg); \
if (ok == EXPECT) \
user_set_info(inf_user, 0); \
return ok == EXPECT;
return ok == EXPECT; \
} while(0)
EXO_TEST(inf_ok_1, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", 0); });
@@ -107,12 +110,15 @@ EXO_TEST(inf_nick_08, { CHECK_INF("BINF AAAB NIa\\nc IDGNSSMURMD7K466NGZIHU65TP3
EXO_TEST(inf_nick_09, { CHECK_INF("BINF AAAB NIabc NIdef IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_multiple); });
EXO_TEST(inf_nick_10, {
const char* line = "BINF AAAB IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n";
int ok;
char nick[10];
struct adc_message* msg;
nick[0] = 0xf7; nick[1] = 0x80; nick[2] = 0x7f; nick[3] = 0x81; nick[4] = 0x98; nick[5] = 0x00;
struct adc_message* msg = adc_msg_parse_verify(inf_user, line, strlen(line));
msg = adc_msg_parse_verify(inf_user, line, strlen(line));
adc_msg_add_named_argument(msg, "NI", nick);
int ok = hub_handle_info_login(inf_hub, inf_user, msg);
ok = hub_handle_info_login(inf_hub, inf_user, msg);
adc_msg_free(msg);
if (ok != status_msg_inf_error_nick_not_utf8)
printf("Expected %d, got %d\n", status_msg_inf_error_nick_not_utf8, ok);

View File

@@ -429,44 +429,51 @@ EXO_TEST(check_ban_ipv4_5, {
});
EXO_TEST(check_ban_ipv6_1, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:0", &addr);
ip_convert_to_binary("2001::201:2ff:fefa:0", &addr);
return ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_2, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:1", &addr);
ip_convert_to_binary("2001::201:2ff:fefa:1", &addr);
return ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_3, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:fffe", &addr);
ip_convert_to_binary("2001::201:2ff:fefa:fffe", &addr);
return ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_4, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:ffff", &addr);
ip_convert_to_binary("2001::201:2ff:fefa:ffff", &addr);
return ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_5, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefb:0", &addr);
ip_convert_to_binary("2001::201:2ff:fefb:0", &addr);
return !ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_6, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
return !ip_in_range(&addr, &ban6);
});
EXO_TEST(check_ban_afmix_1, {
struct ip_addr_encap addr;
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
return !ip_in_range(&addr, &ban4);
});
@@ -610,8 +617,10 @@ EXO_TEST(ip_range_3, {
});
EXO_TEST(ip_range_4, {
struct ip_range range1; memset(&range1, 0, sizeof(range1));
struct ip_range range2; memset(&range2, 0, sizeof(range2));
struct ip_range range1;
struct ip_range range2;
memset(&range1, 0, sizeof(range1));
memset(&range2, 0, sizeof(range2));
return ip_convert_address_to_range("192.168.0.0/16", &range1) && ip_convert_address_to_range("192.168.0.0-192.168.255.255", &range2) && memcmp(&range1, &range2, sizeof(struct ip_range)) == 0;
});

View File

@@ -174,91 +174,102 @@ EXO_TEST(adc_message_parse_24, {
EXO_TEST(adc_message_add_arg_1, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_argument(msg, "XXwtf?");
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_add_arg_2, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_named_argument(msg, "XX", "wtf?");
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat XXwtf?\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_remove_arg_1, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "AA");
int ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_remove_arg_2, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "BB");
int ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_remove_arg_3, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "CC");
int ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_remove_arg_4, {
/* this ensures we can remove the last element also */
int ok;
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string3, strlen(test_string3));
adc_msg_remove_named_argument(msg, "AW");
int ok = strcmp(msg->cache, "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1\n") == 0;
ok = strcmp(msg->cache, "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_replace_arg_1, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "AA");
int ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF BBbar CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_replace_arg_2, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "BB");
int ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_replace_arg_3, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_remove_named_argument(msg, "CC");
int ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_get_arg_1, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
char* c = adc_msg_get_argument(msg, 0);
int ok = strcmp(c, "AAfoo") == 0;
ok = strcmp(c, "AAfoo") == 0;
adc_msg_free(msg);
hub_free(c);
return ok;
});
EXO_TEST(adc_message_get_arg_2, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
char* c = adc_msg_get_argument(msg, 1);
int ok = strcmp(c, "BBbar") == 0;
ok = strcmp(c, "BBbar") == 0;
adc_msg_free(msg);
hub_free(c);
return ok;
@@ -340,28 +351,31 @@ EXO_TEST(adc_message_has_named_arg_3, {
});
EXO_TEST(adc_message_has_named_arg_4, {
int n;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_argument(msg, "XXwtf?");
int n = adc_msg_has_named_argument(msg, "XX");
n = adc_msg_has_named_argument(msg, "XX");
adc_msg_free(msg);
return n == 1;
});
EXO_TEST(adc_message_has_named_arg_5, {
int n;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_argument(msg, "XXone");
adc_msg_add_argument(msg, "XXtwo");
int n = adc_msg_has_named_argument(msg, "XX");
n = adc_msg_has_named_argument(msg, "XX");
adc_msg_free(msg);
return n == 2;
});
EXO_TEST(adc_message_has_named_arg_6, {
int n;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_argument(msg, "XXone");
adc_msg_add_argument(msg, "XXtwo");
adc_msg_add_argument(msg, "XXthree");
int n = adc_msg_has_named_argument(msg, "XX");
n = adc_msg_has_named_argument(msg, "XX");
adc_msg_free(msg);
return n == 3;
});
@@ -374,63 +388,70 @@ EXO_TEST(adc_message_has_named_arg_7, {
});
EXO_TEST(adc_message_terminate_1, {
int ok;
struct adc_message* msg = adc_msg_create("IINF AAfoo BBbar CCwhat");
adc_msg_unterminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_terminate_2, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_unterminate(msg);
adc_msg_terminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_terminate_3, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_unterminate(msg);
adc_msg_terminate(msg);
adc_msg_unterminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_terminate_4, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_unterminate(msg);
adc_msg_terminate(msg);
adc_msg_terminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_terminate_5, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_terminate(msg);
adc_msg_terminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat\n") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_terminate_6, {
int ok;
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_unterminate(msg);
adc_msg_unterminate(msg);
int ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
ok = strcmp(msg->cache, "IINF AAfoo BBbar CCwhat") == 0;
adc_msg_free(msg);
return ok;
});
EXO_TEST(adc_message_escape_1, {
int ok;
char* s = adc_msg_escape(test_string1);
int ok = strcmp(s, "IINF\\sAAfoo\\sBBbar\\sCCwhat\\n") == 0;
ok = strcmp(s, "IINF\\sAAfoo\\sBBbar\\sCCwhat\\n") == 0;
hub_free(s);
return ok;
});

View File

@@ -97,15 +97,25 @@ EXO_TEST(base32_invalid_31, { return !is_valid_base32_char('@'); });
EXO_TEST(utf8_valid_1, { return is_valid_utf8("abcdefghijklmnopqrstuvwxyz"); });
EXO_TEST(utf8_valid_2, { return is_valid_utf8("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); });
EXO_TEST(utf8_valid_3, { return is_valid_utf8("0123456789"); });
EXO_TEST(utf8_valid_4, { return is_valid_utf8( (char[]) { 0x65, 0x00} ); });
EXO_TEST(utf8_valid_5, { return !is_valid_utf8( (char[]) { 0xD8, 0x00} ); });
EXO_TEST(utf8_valid_6, { return is_valid_utf8( (char[]) { 0x24, 0x00} ); });
EXO_TEST(utf8_valid_7, { return !is_valid_utf8( (char[]) { 0xC2, 0x24, 0x00} ); });
EXO_TEST(utf8_valid_8, { return is_valid_utf8( (char[]) { 0xC2, 0xA2, 0x00} ); });
EXO_TEST(utf8_valid_9, { return is_valid_utf8( (char[]) { 0xE2, 0x82, 0xAC, 0x00} ); });
EXO_TEST(utf8_valid_10, { return !is_valid_utf8( (char[]) { 0xC2, 0x32, 0x00} ); });
EXO_TEST(utf8_valid_11, { return !is_valid_utf8( (char[]) { 0xE2, 0x82, 0x32, 0x00} ); });
EXO_TEST(utf8_valid_12, { return !is_valid_utf8( (char[]) { 0xE2, 0x32, 0x82, 0x00} ); });
static const char test_utf_seq_1[] = { 0x65, 0x00 }; // valid
static const char test_utf_seq_2[] = { 0xD8, 0x00 }; // invalid
static const char test_utf_seq_3[] = { 0x24, 0x00 }; // valid
static const char test_utf_seq_4[] = { 0xC2, 0x24, 0x00}; // invalid
static const char test_utf_seq_5[] = { 0xC2, 0xA2, 0x00}; // valid
static const char test_utf_seq_6[] = { 0xE2, 0x82, 0xAC, 0x00}; // valid
static const char test_utf_seq_7[] = { 0xC2, 0x32, 0x00}; // invalid
static const char test_utf_seq_8[] = { 0xE2, 0x82, 0x32, 0x00}; // invalid
static const char test_utf_seq_9[] = { 0xE2, 0x32, 0x82, 0x00}; // invalid
EXO_TEST(utf8_valid_4, { return is_valid_utf8(test_utf_seq_1); });
EXO_TEST(utf8_valid_5, { return !is_valid_utf8(test_utf_seq_2); });
EXO_TEST(utf8_valid_6, { return is_valid_utf8(test_utf_seq_3); });
EXO_TEST(utf8_valid_7, { return !is_valid_utf8(test_utf_seq_4); });
EXO_TEST(utf8_valid_8, { return is_valid_utf8(test_utf_seq_5); });
EXO_TEST(utf8_valid_9, { return is_valid_utf8(test_utf_seq_6); });
EXO_TEST(utf8_valid_10, { return !is_valid_utf8(test_utf_seq_7); });
EXO_TEST(utf8_valid_11, { return !is_valid_utf8(test_utf_seq_8); });
EXO_TEST(utf8_valid_12, { return !is_valid_utf8(test_utf_seq_9); });

144
autotest/test_rbtree.tcc Normal file
View File

@@ -0,0 +1,144 @@
#include <uhub.h>
#include <util/rbtree.h>
#define MAX_NODES 10000
static struct rb_tree* tree = NULL;
int test_tree_compare(const void* a, const void* b)
{
return strcmp((const char*) a, (const char*) b);
}
EXO_TEST(rbtree_create_destroy, {
int ok = 0;
struct rb_tree* atree;
atree = rb_tree_create(test_tree_compare, &hub_malloc, &hub_free);
if (atree) ok = 1;
rb_tree_destroy(atree);
return ok;
});
EXO_TEST(rbtree_create_1, {
tree = rb_tree_create(test_tree_compare, &hub_malloc, &hub_free);
return tree != NULL;
});
EXO_TEST(rbtree_size_0, { return rb_tree_size(tree) == 0; });
EXO_TEST(rbtree_insert_1, {
return rb_tree_insert(tree, "one", "1");
});
EXO_TEST(rbtree_insert_2, {
return rb_tree_insert(tree, "two", "2");
});
EXO_TEST(rbtree_insert_3, {
return rb_tree_insert(tree, "three", "3");
});
EXO_TEST(rbtree_insert_3_again, {
return !rb_tree_insert(tree, "three", "3-again");
});
EXO_TEST(rbtree_size_1, { return rb_tree_size(tree) == 3; });
static int test_check_search(const char* key, const char* expect)
{
const char* value = (const char*) rb_tree_get(tree, key);
if (!value) return !expect;
if (!expect) return 0;
return strcmp(value, expect) == 0;
}
EXO_TEST(rbtree_search_1, { return test_check_search("one", "1"); });
EXO_TEST(rbtree_search_2, { return test_check_search("two", "2"); });
EXO_TEST(rbtree_search_3, { return test_check_search("three", "3"); });
EXO_TEST(rbtree_search_4, { return test_check_search("four", NULL); });
EXO_TEST(rbtree_remove_1, {
return rb_tree_remove(tree, "one");
});
EXO_TEST(rbtree_size_2, { return rb_tree_size(tree) == 2; });
EXO_TEST(rbtree_remove_2, {
return rb_tree_remove(tree, "two");
});
EXO_TEST(rbtree_remove_3, {
return rb_tree_remove(tree, "three");
});
EXO_TEST(rbtree_remove_3_again, {
return !rb_tree_remove(tree, "three");
});
EXO_TEST(rbtree_search_5, { return test_check_search("one", NULL); });
EXO_TEST(rbtree_search_6, { return test_check_search("two", NULL); });
EXO_TEST(rbtree_search_7, { return test_check_search("three", NULL); });
EXO_TEST(rbtree_search_8, { return test_check_search("four", NULL); });
EXO_TEST(rbtree_size_3, { return rb_tree_size(tree) == 0; });
EXO_TEST(rbtree_insert_10000, {
int i;
for (i = 0; i < MAX_NODES ; i++)
{
const char* key = strdup(uhub_itoa(i));
const char* val = strdup(uhub_itoa(i + 16384));
if (!rb_tree_insert(tree, key, val))
return 0;
}
return 1;
});
EXO_TEST(rbtree_size_4, { return rb_tree_size(tree) == MAX_NODES ; });
EXO_TEST(rbtree_check_10000, {
int i;
for (i = 0; i < MAX_NODES ; i++)
{
char* key = strdup(uhub_itoa(i));
const char* expect = uhub_itoa(i + 16384);
if (!test_check_search(key, expect))
return 0;
hub_free(key);
}
return 1;
});
EXO_TEST(rbtree_iterate_10000, {
int i = 0;
struct rb_node* n = (struct rb_node*) rb_tree_first(tree);
while (n)
{
struct rb_node* p = n;
n = (struct rb_node*) rb_tree_next(tree);
i++;
}
return i == MAX_NODES ;
});
static void free_node(struct rb_node* n)
{
hub_free((void*) n->key);
hub_free((void*) n->value);
}
EXO_TEST(rbtree_remove_5000, {
int i = 0;
struct rb_node* n = (struct rb_node*) rb_tree_first(tree);
for (i = 0; i < MAX_NODES ; i += 2)
{
const char* key = uhub_itoa(i);
rb_tree_remove_node(tree, key, &free_node);
}
return 1;
});

View File

@@ -1,6 +1,6 @@
#include <uhub.h>
#define MAX_EVENTS 15
#define MAX_EVENTS 100
static struct timeout_queue* g_queue;
static time_t g_now;
static size_t g_max;
@@ -117,3 +117,28 @@ EXO_TEST(timer_process_5_events_1,{
g_now = 4;
return timeout_queue_process(g_queue, g_now) == g_triggered;
});
EXO_TEST(timer_clear_1,{
size_t n;
for (n = 0; n < MAX_EVENTS; n++)
timeout_queue_remove(g_queue, &g_events[n]);
return timeout_queue_get_next_timeout(g_queue, g_now) == g_max;
});
EXO_TEST(timer_bulk_1,{
size_t n;
g_now = 10;
for (n = 0; n < MAX_EVENTS; n++)
{
timeout_queue_insert(g_queue, &g_events[0], 0);
}
return timeout_queue_process(g_queue, g_now) == 10;
});
EXO_TEST(timer_bulk_2,{
g_now = 110;
return timeout_queue_process(g_queue, g_now) == 90;
});

View File

@@ -7,13 +7,15 @@
static int match_str(const char* str1, char* str2)
{
size_t i;
int ret;
for (i = 0; i < strlen(str2); i++)
if (str2[i] == '_')
str2[i] = ' ';
else if (str2[i] == '|')
str2[i] = '\t';
int ret = strcmp(str1, str2);
ret = strcmp(str1, str2);
if (ret) {
fprintf(stderr, "\n Mismatch: \"%s\" != \"%s\"\n", str1, str2);
}
@@ -29,10 +31,11 @@ static int count(const char* STR, size_t EXPECT) {
static int compare(const char* str, const char* ref) {
size_t i, max;
int pass;
struct linked_list* compare = list_create();
SETUP(tokens, str);
split_string(ref, " ", compare, 0);
int pass = cfg_token_count(tokens) == list_size(compare);
pass = cfg_token_count(tokens) == list_size(compare);
if (pass) {
max = cfg_token_count(tokens);
for (i = 0; i < max; i++) {

4
autotest/update.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
./exotic *.tcc > test.c

View File

@@ -0,0 +1,77 @@
# - Try to find sqlite3
# Find sqlite3 headers, libraries and the answer to all questions.
#
# SQLITE3_FOUND True if sqlite3 got found
# SQLITE3_INCLUDEDIR Location of sqlite3 headers
# SQLITE3_LIBRARIES List of libaries to use sqlite3
# SQLITE3_DEFINITIONS Definitions to compile sqlite3
#
# Copyright (c) 2007 Juha Tuomala <tuju@iki.fi>
# Copyright (c) 2007 Daniel Gollub <gollub@b1-systems.de>
# Copyright (c) 2007 Alban Browaeys <prahal@yahoo.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
INCLUDE( FindPkgConfig )
# Take care about sqlite3.pc settings
IF ( Sqlite3_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "REQUIRED" )
ELSE ( Sqlite3_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "" )
ENDIF ( Sqlite3_FIND_REQUIRED )
IF ( SQLITE3_MIN_VERSION )
PKG_SEARCH_MODULE( SQLITE3 ${_pkgconfig_REQUIRED} sqlite3>=${SQLITE3_MIN_VERSION} )
ELSE ( SQLITE3_MIN_VERSION )
pkg_search_module( SQLITE3 ${_pkgconfig_REQUIRED} sqlite3 )
ENDIF ( SQLITE3_MIN_VERSION )
# Look for sqlite3 include dir and libraries w/o pkgconfig
IF ( NOT SQLITE3_FOUND AND NOT PKG_CONFIG_FOUND )
FIND_PATH( _sqlite3_include_DIR sqlite3.h
PATHS
/opt/local/include/
/sw/include/
/usr/local/include/
/usr/include/
)
FIND_LIBRARY( _sqlite3_link_DIR sqlite3
PATHS
/opt/local/lib
/sw/lib
/usr/lib
/usr/local/lib
/usr/lib64
/usr/local/lib64
/opt/lib64
)
IF ( _sqlite3_include_DIR AND _sqlite3_link_DIR )
SET ( _sqlite3_FOUND TRUE )
ENDIF ( _sqlite3_include_DIR AND _sqlite3_link_DIR )
IF ( _sqlite3_FOUND )
SET ( SQLITE3_INCLUDE_DIRS ${_sqlite3_include_DIR} )
SET ( SQLITE3_LIBRARIES ${_sqlite3_link_DIR} )
ENDIF ( _sqlite3_FOUND )
# Report results
IF ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
SET( SQLITE3_FOUND 1 )
MESSAGE( STATUS "Found sqlite3: ${SQLITE3_LIBRARIES} ${SQLITE3_INCLUDE_DIRS}" )
ELSE ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
IF ( Sqlite3_FIND_REQUIRED )
MESSAGE( SEND_ERROR "Could NOT find sqlite3" )
ELSE ( Sqlite3_FIND_REQUIRED )
MESSAGE( STATUS "Could NOT find sqlite3" )
ENDIF ( Sqlite3_FIND_REQUIRED )
ENDIF ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
ENDIF ( NOT SQLITE3_FOUND AND NOT PKG_CONFIG_FOUND )
# Hide advanced variables from CMake GUIs
MARK_AS_ADVANCED( SQLITE3_LIBRARIES SQLITE3_INCLUDE_DIRS )

View File

@@ -787,6 +787,13 @@ int adc_msg_add_argument(struct adc_message* cmd, const char* string)
return 0;
}
int adc_msg_add_argument_string(struct adc_message* cmd, const char* string)
{
char* escaped = adc_msg_escape(string);
int ret = adc_msg_add_argument(cmd, escaped);
hub_free(escaped);
return ret;
}
char* adc_msg_get_argument(struct adc_message* cmd, int offset)
{
@@ -866,8 +873,6 @@ int adc_msg_get_argument_index(struct adc_message* cmd, const char prefix[2])
return -1;
}
int adc_msg_escape_length(const char* str)
{
int add = 0;

View File

@@ -171,6 +171,12 @@ extern int adc_msg_replace_named_argument(struct adc_message* cmd, const char pr
*/
extern int adc_msg_add_argument(struct adc_message* cmd, const char* string);
/**
* Add an argument string, the string will be automatcally escaped.
* @return 0 if successful, or -1 if an error occured (out of memory).
*/
extern int adc_msg_add_argument_string(struct adc_message* cmd, const char* string);
/**
* Append a named argument
*
@@ -209,6 +215,13 @@ extern char* adc_msg_unescape(const char* string);
*/
extern int adc_msg_unescape_to_target(const char* string, char* target, size_t target_size);
/**
* Returns the length of the string once escaped with
* adc_msg_escape().
*
* The string must be NULL terminated.
*/
extern int adc_msg_escape_length(const char* str);
/**
* Convert a string to a ADC command escaped string.
@@ -234,4 +247,5 @@ void adc_msg_unterminate(struct adc_message* cmd);
*/
int adc_msg_get_arg_offset(struct adc_message* msg);
#endif /* HAVE_UHUB_COMMAND_H */

View File

@@ -353,6 +353,7 @@ static int command_kick(struct command_base* cbase, struct hub_user* user, struc
}
else
{
hub_notify(cbase->hub, notify_info, "Kicking user \"%s\" (%s)", target->id.nick, user->id.nick);
cbuf_append_format(buf, "Kicking user \"%s\".", target->id.nick);
hub_disconnect_user(cbase->hub, target, quit_kicked);
}
@@ -362,6 +363,7 @@ static int command_kick(struct command_base* cbase, struct hub_user* user, struc
static int command_reload(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
{
cbase->hub->status = hub_status_restart;
hub_notify(cbase->hub, notify_info, "Reloading configuration (%s)", user->id.nick);
return command_status(cbase, user, cmd, cbuf_create_const("Reloading configuration..."));
}
@@ -384,6 +386,7 @@ static int command_unload(struct command_base* cbase, struct hub_user* user, str
static int command_shutdown_hub(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
{
hub_notify(cbase->hub, notify_warn, "Shutting down hub (%s)", user->id.nick);
cbase->hub->status = hub_status_shutdown;
return command_status(cbase, user, cmd, cbuf_create_const("Hub shutting down..."));
}

View File

@@ -653,6 +653,7 @@ static struct net_connection* start_listening_socket(const char* bind_addr, uint
if (ret == -1)
{
LOG_ERROR("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
hub_notify(hub, notify_error, "Unable to bind to network address %s on port %d: %s (%d)", bind_addr, port, net_error_string(net_error()), net_error());
net_close(sd);
return 0;
}
@@ -671,6 +672,60 @@ static struct net_connection* start_listening_socket(const char* bind_addr, uint
return server;
}
int hub_is_running(struct hub_info* hub)
{
return hub->status == hub_status_running || hub->status == hub_status_restart;
}
void hub_notify(struct hub_info* hub, enum notify_verbosity verbosity, const char* fmt, ...)
{
struct cbuffer* buf;
struct adc_message* msg;
va_list args;
char temp[1024];
va_start(args, fmt);
vsnprintf(temp, sizeof(temp), fmt, args);
va_end(args);
buf = cbuf_create(strlen(temp) + 8);
switch (verbosity)
{
case notify_error:
cbuf_append(buf, "ERROR: ");
LOG_ERROR(temp);
break;
case notify_warn:
cbuf_append(buf, "WARN: ");
LOG_WARN(temp);
break;
case notify_info:
cbuf_append(buf, "INFO: ");
LOG_INFO(temp);
break;
case notify_debug:
cbuf_append(buf, "DEBUG: ");
LOG_DEBUG(temp);
break;
}
cbuf_append(buf, temp);
if (hub_is_running(hub))
{
msg = adc_msg_construct(ADC_CMD_IMSG, 5 + adc_msg_escape_length(cbuf_get(buf)) + 2);
adc_msg_add_argument_string(msg, cbuf_get(buf));
route_to_operators(hub, msg);
adc_msg_free(msg);
}
cbuf_destroy(buf);
}
struct server_alt_port_data
{
struct hub_info* hub;
@@ -751,6 +806,54 @@ static void unload_ssl_certificates(struct hub_info* hub)
}
#endif /* SSL_SUPPORT */
// #ifdef BOT_SUPPORT
static void route_privmsg_to_operators(struct hub_user* bot, sid_t from, const char* escaped_msg, int action)
{
struct hub_info* hub = bot->hub;
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (from != user->id.sid && user_flag_get(user, flag_opnotify))
{
struct adc_message* msg = adc_msg_construct_source_dest(ADC_CMD_EMSG, from, user->id.sid, strlen(escaped_msg) + (action * 4) + 7);
adc_msg_add_argument(msg, escaped_msg);
adc_msg_add_named_argument(msg, ADC_MSG_FLAG_PRIVATE, sid_to_string(bot->id.sid));
if (action) adc_msg_add_named_argument(msg, ADC_MSG_FLAG_ACTION, "1");
route_to_user(hub, user, msg);
adc_msg_free(msg);
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
}
/// This receives private messages and transmits them to the connected operators.
static void hub_bot_op_notify_handle(struct hub_user* bot, struct adc_message* msg)
{
char* chat;
LOG_TRACE("Invoked hub_bot_op_notify_handle()");
switch (msg->cmd)
{
case ADC_CMD_EMSG:
case ADC_CMD_DMSG:
chat = adc_msg_get_argument(msg, 0);
LOG_DEBUG("Hub chat: \"%s\"", chat);
route_privmsg_to_operators(bot, msg->source, chat, adc_msg_has_named_argument(msg, ADC_MSG_FLAG_ACTION) ? 1 : 0);
hub_free(chat);
break;
default:
/* ignore these messages! */
break;
}
}
static void hub_bot_op_notify_create(struct hub_info* hub)
{
struct hub_user* opcom = user_create_bot(hub, "Operations", "Hub operators", hub_bot_op_notify_handle);
uman_add(hub->users, opcom);
}
// #endif
struct hub_info* hub_start_service(struct hub_config* config)
{
struct hub_info* hub = 0;
@@ -834,6 +937,8 @@ struct hub_info* hub_start_service(struct hub_config* config)
// Start the hub command sub-system
hub->commands = command_initialize(hub);
hub_bot_op_notify_create(hub);
return hub;
}

View File

@@ -106,7 +106,7 @@ struct hub_info
struct adc_message* command_support; /* The hub's SUP command */
struct adc_message* command_banner; /* The default welcome message */
time_t tm_started;
int status;
enum hub_state status;
char* recvbuf; /* Global receive buffer */
char* sendbuf; /* Global send buffer */
@@ -233,6 +233,20 @@ extern void hub_set_variables(struct hub_info* hub, struct acl_handle* acl);
*/
extern void hub_free_variables(struct hub_info* hub);
enum notify_verbosity
{
notify_error = 0,
notify_warn = 1,
notify_info = 2,
notify_debug = 3,
};
/**
* Send a notification message to operators.
*/
extern void hub_notify(struct hub_info* hub, enum notify_verbosity verbosity, const char* fmt, ...);
/**
* Returns a string for the given status_message (See enum status_message).
*/
@@ -350,6 +364,10 @@ extern void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int
*/
extern void hub_logout_log(struct hub_info* hub, struct hub_user* user);
/**
* Returns 1 if the hub is running, and 0 otherwise.
*/
extern int hub_is_running(struct hub_info* hub);
#endif /* HAVE_UHUB_HUB_H */

View File

@@ -31,6 +31,10 @@ void on_login_success(struct hub_info* hub, struct hub_user* u)
user_set_state(u, state_normal);
uman_add(hub->users, u);
// Make operators receive hub notifications by default.
if (user_is_protected(u))
user_flag_set(u, flag_opnotify);
/* Announce new user to all connected users */
if (user_is_logged_in(u))
route_info_message(hub, u);

View File

@@ -19,6 +19,10 @@
#include "uhub.h"
#ifdef SYSTEMD
#include <systemd/sd-daemon.h>
#endif
static int arg_verbose = 5;
static int arg_fork = 0;
static int arg_check_config = 0;
@@ -145,7 +149,16 @@ int main_loop()
}
#if !defined(WIN32)
setup_signal_handlers(hub);
#endif
#ifdef SYSTEMD
/* Notify the service manager that this daemon has
* been successfully initalized and shall enter the
* main loop.
*/
sd_notifyf(0, "READY=1\n"
"MAINPID=%lu", (unsigned long) getpid());
#endif /* SYSTEMD */
#endif /* ! WIN32 */
}
hub_set_variables(hub, &acl);
@@ -216,13 +229,17 @@ void print_usage(char* program)
" -q Quiet mode - no output\n"
" -f Fork to background\n"
" -l <file> Log messages to given file (default: stderr)\n"
" -L Log messages to syslog\n"
" -c <file> Specify configuration file (default: " SERVER_CONFIG ")\n"
" -C Check configuration and return\n"
" -s Show configuration parameters\n"
" -S Show configuration parameters, but ignore defaults\n"
" -h This message\n"
#ifndef WIN32
#ifdef SYSTEMD
" -L Log messages to journal\n"
#else
" -L Log messages to syslog\n"
#endif
" -u <user> Run as given user\n"
" -g <group> Run with given group permissions\n"
" -p <file> Store pid in file (process id)\n"

View File

@@ -104,7 +104,7 @@ static int cbfunc_command_add(struct plugin_handle* plugin, struct plugin_comman
cmdh->internal_handle = command;
list_append(data->commands, cmdh);
command_add(plugin_get_hub(plugin)->commands, command, (void*) plugin);
printf("*** Add plugin command: %s (%p, %p)\n", command->prefix, command, cmdh);
LOG_DEBUG("*** Add plugin command: %s (%p, %p)\n", command->prefix, command, cmdh);
return 0;
}
@@ -113,7 +113,7 @@ static int cbfunc_command_del(struct plugin_handle* plugin, struct plugin_comman
struct plugin_callback_data* data = get_callback_data(plugin);
struct command_handle* command = (struct command_handle*) cmdh->internal_handle;
printf("*** Del plugin command: %s (%p, %p)\n", command->prefix, command, cmdh);
LOG_DEBUG("*** Del plugin command: %s (%p, %p)\n", command->prefix, command, cmdh);
list_remove(data->commands, cmdh);
command_del(plugin_get_hub(plugin)->commands, command);
hub_free(command);

View File

@@ -104,7 +104,19 @@ int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_messag
#endif
if (!user->connection)
{
switch (user->type)
{
case user_type_client:
return 0; // No connection - we're about to drop this user.
case user_type_bot:
{
bot_recv_msg handler = (bot_recv_msg) user->ptr;
handler(user, msg);
return 0;
}
}
}
uhub_assert(msg->cache && *msg->cache);
@@ -149,6 +161,19 @@ int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate u
return 0;
}
int route_to_operators(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (user_flag_get(user, flag_opnotify))
route_to_user(hub, user, command);
user = (struct hub_user*) list_get_next(hub->users->list);
}
return 0;
}
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
int do_send;

View File

@@ -40,6 +40,14 @@ extern int route_to_user(struct hub_info* hub, struct hub_user*, struct adc_mess
*/
extern int route_to_all(struct hub_info* hub, struct adc_message* command);
/**
* Send a message to all operators.
* Technically it sends to all users with the flag_opnotify set
* which is intended to be set for only operators - allowing operators to opt-out
* of these messages.
*/
extern int route_to_operators(struct hub_info* hub, struct adc_message* command);
/**
* Broadcast message to all users subscribing to the type of message.
*/

View File

@@ -42,7 +42,6 @@ struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, s
LOG_TRACE("user_create(), hub=%p, con[sd=%d]", hub, net_con_get_sd(con));
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL)
return NULL; /* OOM */
@@ -54,6 +53,7 @@ struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, s
memcpy(&user->id.addr, addr, sizeof(struct ip_addr_encap));
user_set_state(user, state_protocol);
user->type = user_type_client;
flood_control_reset(&user->flood_chat);
flood_control_reset(&user->flood_connect);
@@ -65,6 +65,54 @@ struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, s
return user;
}
/// generate a semi-stable CID: base32_encode(tiger({hub name} + {nick}))
static const char* generate_bot_cid(struct hub_info* hub, const char* nick)
{
static char result[MAX_CID_LEN+1];
char buf[(MAX_NICK_LEN*2)+1];
uint64_t tiger_res[3];
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "%s%s", hub->config->hub_name, nick);
tiger((uint64_t*) buf, sizeof(buf), (uint64_t*) tiger_res);
base32_encode((unsigned char*) tiger_res, TIGERSIZE, result);
result[MAX_CID_LEN] = 0;
return result;
}
struct hub_user* user_create_bot(struct hub_info* hub, const char* nick, const char* description, bot_recv_msg msg_handler)
{
struct hub_user* user = NULL;
LOG_TRACE("user_create_bot(), hub=%p, nick=\"%s\"", hub, nick);
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL)
return NULL; /* OOM */
strcpy(user->id.nick, nick);
uman_get_free_sid(hub->users, user);
user_set_state(user, state_normal);
user->type = user_type_bot;
user->credentials = auth_cred_bot;
// The message handler
user->ptr = (void*) msg_handler;
user->info = adc_msg_construct(ADC_CMD_BINF, 15);
if (user->info)
{
adc_msg_add_argument(user->info, sid_to_string(user->id.sid));
adc_msg_add_named_argument(user->info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_BOT);
adc_msg_add_named_argument_string(user->info, ADC_INF_FLAG_USER_AGENT, PRODUCT_STRING);
adc_msg_add_named_argument_string(user->info, ADC_INF_FLAG_NICK, nick);
adc_msg_add_named_argument_string(user->info, ADC_INF_FLAG_DESCRIPTION, description);
adc_msg_add_named_argument(user->info, ADC_INF_FLAG_CLIENT_ID, generate_bot_cid(hub, nick));
}
user->hub = hub;
return user;
}
void user_destroy(struct hub_user* user)
{

View File

@@ -47,6 +47,7 @@ enum user_flags
feature_link = 0x00000100, /** LINK: Hub link (not supported) */
feature_adcs = 0x00000200, /** ADCS: ADC over TLS/SSL */
feature_bas0 = 0x00000400, /** BAS0: Obsolete pre-ADC/1.0 protocol version */
flag_opnotify = 0x00200000, /** User should receive operation notifications. NOTE: Only operators should have this flag! */
flag_flood = 0x00400000, /** User has been notified about flooding. */
flag_muted = 0x00800000, /** User is muted (cannot chat) */
flag_ignore = 0x01000000, /** Ignore further reads */
@@ -104,21 +105,30 @@ struct hub_user_limits
size_t hub_count_total; /** The number of hubs connected to in total */
};
enum user_type
{
user_type_client, /** A user connected normally as an ADC client */
user_type_bot, /** Not really a user, but a bot inside the hub */
};
typedef void (*bot_recv_msg)(struct hub_user*, struct adc_message* msg);
struct hub_user
{
struct hub_user_info id; /** Contains nick name and CID */
enum auth_credentials credentials; /** see enum user_credentials */
enum user_state state; /** see enum user_state */
enum user_type type;
uint32_t flags; /** see enum user_flags */
struct linked_list* feature_cast; /** Features supported by feature cast */
struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */
struct hub_info* hub; /** The hub instance this user belong to */
void* ptr;
struct ioq_recv* recv_queue;
struct ioq_send* send_queue;
struct net_connection* connection; /** Connection data */
struct hub_user_limits limits; /** Data used for limitation */
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */
struct flood_control flood_chat;
struct flood_control flood_connect;
struct flood_control flood_search;
@@ -138,6 +148,7 @@ struct hub_user
* @return User object or NULL if not enough memory is available.
*/
extern struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr);
extern struct hub_user* user_create_bot(struct hub_info* hub, const char* nick, const char* description, bot_recv_msg msg_handler);
/**
* Delete a user.

View File

@@ -132,9 +132,10 @@ struct timeout_queue* net_backend_get_timeout_queue()
*/
int net_backend_process()
{
int res;
int res = 0;
size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
if (g_backend->common.num)
res = g_backend->handler.backend_poll(g_backend->data, secs * 1000);
g_backend->now = time(0);

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -145,3 +145,364 @@ void net_con_callback(struct net_connection* con, int events)
con->callback(con, events, con->ptr);
}
struct net_connect_job
{
struct net_connection* con;
struct net_connect_handle* handle;
struct sockaddr_storage addr;
struct net_connect_job* next;
};
struct net_connect_handle
{
const char* address;
uint16_t port;
void* ptr;
net_connect_cb callback;
struct net_dns_job* dns;
const struct net_dns_result* result;
struct net_connect_job* job4;
struct net_connect_job* job6;
};
static void net_connect_callback(struct net_connect_handle* handle, enum net_connect_status status, struct net_connection* con);
static void net_connect_job_internal_cb(struct net_connection* con, int event, void* ptr);
/**
* Check if a connection job is completed.
* @return -1 on completed with an error, 0 on not yet completed, or 1 if completed successfully (connected).
*/
static int net_connect_job_check(struct net_connect_job* job)
{
struct net_connection* con = job->con;
int af = job->addr.ss_family;
enum net_connect_status status;
int ret = net_connect(net_con_get_sd(con), (struct sockaddr*) &job->addr, af == AF_INET ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
LOG_TRACE("net_connect_job_check(): Socket connected!");
job->con = NULL;
net_connect_callback(job->handle, net_connect_status_ok, con);
return 1;
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
return 0;
}
LOG_TRACE("net_connect_job_check(): Socket error!");
switch (net_error())
{
case ECONNREFUSED:
status = net_connect_status_refused;
break;
case ENETUNREACH:
status = net_connect_status_unreachable;
break;
default:
status = net_connect_status_socket_error;
}
net_connect_callback(job->handle, status, NULL);
return -1;
}
static void net_connect_job_free(struct net_connect_job* job)
{
if (job->con)
net_con_close(job->con);
job->handle = NULL;
job->next = NULL;
hub_free(job);
}
static void net_connect_job_stop(struct net_connect_job* job)
{
if (job->addr.ss_family == AF_INET6)
{
job->handle->job6 = job->next;
}
else
{
job->handle->job4 = job->next;
}
net_connect_job_free(job);
}
static int net_connect_depleted(struct net_connect_handle* handle)
{
return (!handle->job6 && !handle->job4);
}
static int net_connect_job_process(struct net_connect_job* job)
{
int sd;
if (!job->con)
{
sd = net_socket_create(job->addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1)
{
LOG_DEBUG("net_connect_job_process: Unable to create socket!");
net_connect_callback(job->handle, net_connect_status_socket_error, NULL);
return -1; // FIXME
}
job->con = net_con_create();
net_con_initialize(job->con, sd, net_connect_job_internal_cb, job, NET_EVENT_WRITE);
net_con_set_timeout(job->con, TIMEOUT_CONNECTED); // FIXME: Use a proper timeout value!
}
return net_connect_job_check(job);
}
/*
* Internal callback used to establish an outbound connection.
*/
static void net_connect_job_internal_cb(struct net_connection* con, int event, void* ptr)
{
int ret;
struct net_connect_job* job = net_con_get_ptr(con);
struct net_connect_job* next_job = job->next;
struct net_connect_handle* handle = job->handle;
if (event == NET_EVENT_TIMEOUT)
{
// FIXME: Try next address, or if no more addresses left declare failure to connect.
if (job->addr.ss_family == AF_INET6)
{
net_connect_job_stop(job);
if (!next_job)
{
LOG_TRACE("No more IPv6 addresses to try!");
}
}
else
{
net_connect_job_stop(job);
if (!next_job)
{
LOG_TRACE("No more IPv4 addresses to try!");
}
}
if (net_connect_depleted(handle))
{
LOG_TRACE("No more addresses left. Unable to connect!");
net_connect_callback(handle, net_connect_status_timeout, NULL);
}
return;
}
if (event == NET_EVENT_WRITE)
{
net_connect_job_process(job);
}
}
static int net_connect_cancel(struct net_connect_handle* handle)
{
struct net_connect_job* job;
job = handle->job6;
while (job)
{
job = job->next;
net_connect_job_free(handle->job6);
handle->job6 = job;
}
job = handle->job4;
while (job)
{
job = job->next;
net_connect_job_free(handle->job4);
handle->job4 = job;
}
}
static int net_connect_process_queue(struct net_connect_handle* handle, struct net_connect_job* job)
{
int ret;
while (job)
{
ret = net_connect_job_process(job);
if (ret < 0)
{
net_connect_job_stop(job);
continue;
}
else if (ret == 0)
{
// Need to process again
return 0;
}
else
{
// FIXME: Success!
return 1;
}
}
return -1;
}
static int net_connect_process(struct net_connect_handle* handle)
{
int ret4, ret6;
ret6 = net_connect_process_queue(handle, handle->job6);
if (ret6 == 1)
return 1; // Connected - cool!
net_connect_process_queue(handle, handle->job4);
}
static int net_connect_job_schedule(struct net_connect_handle* handle, struct ip_addr_encap* addr)
{
struct net_connect_job* job;
struct sockaddr_in* addr4;
struct sockaddr_in6* addr6;
if (addr->af == AF_INET6 && !net_is_ipv6_supported())
{
LOG_TRACE("net_connect_job_schedule(): Skipping IPv6 support since IPv6 is not supported.");
return 0;
}
else
{
job = hub_malloc_zero(sizeof(struct net_connect_job));
job->handle = handle;
if (addr->af == AF_INET6)
{
addr6 = (struct sockaddr_in6*) &job->addr;
LOG_TRACE("net_connect_job_schedule(): Scheduling IPv6 connect job.");
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(handle->port);
memcpy(&addr6->sin6_addr, &addr->internal_ip_data.in6, sizeof(struct in6_addr));
// prepend
job->next = handle->job6;
handle->job6 = job;
}
else
{
addr4 = (struct sockaddr_in*) &job->addr;
LOG_TRACE("net_connect_job_schedule(): Scheduling IPv4 connect job.");
addr4->sin_family = AF_INET;
addr4->sin_port = htons(handle->port);
memcpy(&addr4->sin_addr, &addr->internal_ip_data.in, sizeof(struct in_addr));
// prepend
job->next = handle->job4;
handle->job4 = job;
}
}
return 1;
}
/*
* Callback when the DNS results are ready.
* Create a list of IPv6 and IPv4 addresses, then
* start connecting to them one by one until one succeeds.
*/
static int net_con_connect_dns_callback(struct net_dns_job* job, const struct net_dns_result* result)
{
struct ip_addr_encap* addr;
struct net_connect_handle* handle = (struct net_connect_handle*) net_dns_job_get_ptr(job);
handle->dns = NULL;
size_t usable = 0;
int ret;
LOG_TRACE("net_con_connect(): async - Got DNS results");
if (!result)
{
LOG_DEBUG("net_con_connect() - Unable to lookup host!");
net_connect_callback(handle, net_connect_status_dns_error, NULL);
return 1;
}
if (!net_dns_result_size(result))
{
LOG_DEBUG("net_con_connect() - Host not found!");
net_connect_callback(handle, net_connect_status_host_not_found, NULL);
return 1;
}
handle->result = result;
// Extract results into a separate list of IPv4 and IPv6 addresses.
addr = net_dns_result_first(result);
while (addr)
{
if (net_connect_job_schedule(handle, addr))
usable++;
addr = net_dns_result_next(result);
}
net_connect_process(handle);
return 0;
}
// typedef void (*net_connect_cb)(struct net_connect_handle*, enum net_connect_handle_code, struct net_connection* con);
struct net_connect_handle* net_con_connect(const char* address, uint16_t port, net_connect_cb callback, void* ptr)
{
struct net_connect_handle* handle = hub_malloc_zero(sizeof(struct net_connect_handle));
handle->address = hub_strdup(address);
handle->port = port;
handle->ptr = ptr;
handle->callback = callback;
// FIXME: Check if DNS resolving is necessary ?
handle->dns = net_dns_gethostbyname(address, AF_UNSPEC, net_con_connect_dns_callback, handle);
if (!handle->dns)
{
LOG_TRACE("net_con_connect(): Unable to create DNS lookup job.");
hub_free((char*) handle->address);
hub_free(handle);
return NULL;
}
return handle;
}
void net_connect_destroy(struct net_connect_handle* handle)
{
hub_free((char*) handle->address);
// cancel DNS job if pending
if (handle->dns)
net_dns_job_cancel(handle->dns);
// Stop any connect jobs.
net_connect_cancel(handle);
// free any DNS results
net_dns_result_free(handle->result);
hub_free(handle);
}
static void net_connect_callback(struct net_connect_handle* handle, enum net_connect_status status, struct net_connection* con)
{
uhub_assert(handle->callback != NULL);
// Call the callback
handle->callback(handle, status, con, handle->ptr);
handle->callback = NULL;
// Cleanup
net_connect_destroy(handle);
}

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,10 +34,41 @@ struct net_connection
NET_CON_STRUCT_COMMON
};
struct net_connect_handle;
enum net_connect_status
{
net_connect_status_ok = 0,
net_connect_status_host_not_found = -1,
net_connect_status_no_address = -2,
net_connect_status_dns_error = -3,
net_connect_status_refused = -4,
net_connect_status_unreachable = -5,
net_connect_status_timeout = -6,
net_connect_status_socket_error = -7,
};
typedef void (*net_connect_cb)(struct net_connect_handle*, enum net_connect_status status, struct net_connection* con, void* ptr);
extern int net_con_get_sd(struct net_connection* con);
extern void* net_con_get_ptr(struct net_connection* con);
extern struct net_connection* net_con_create();
/**
* Establish an outbound TCP connection.
* This will resolve the IP-addresses, and connect to
* either an IPv4 or IPv6 address depending if it is supported,
* and using the happy eyeballs algorithm.
*
* @param address Hostname, IPv4 or IPv6 address
* @param port TCP port number
* @param callback A callback to be called once the connection is established, or failed.
* @returns a handle to the connection establishment job, or NULL if an immediate error.
*/
extern struct net_connect_handle* net_con_connect(const char* address, uint16_t port, net_connect_cb callback, void* ptr);
extern void net_connect_destroy(struct net_connect_handle* handle);
extern void net_con_destroy(struct net_connection*);
extern void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events);
extern void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events);

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -366,21 +366,24 @@ extern size_t net_dns_result_size(const struct net_dns_result* res)
extern struct ip_addr_encap* net_dns_result_first(const struct net_dns_result* res)
{
struct ip_addr_encap* ipaddr = list_get_first(res->addr_list);
LOG_TRACE("net_dns_result_first() - Address: %s", ip_convert_to_string(ipaddr));
LOG_TRACE("net_dns_result_first() - Address: %s", ipaddr ? ip_convert_to_string(ipaddr) : "(no address)");
return ipaddr;
}
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result* res)
{
struct ip_addr_encap* ipaddr = list_get_next(res->addr_list);
LOG_TRACE("net_dns_result_next() - Address: %s", ip_convert_to_string(ipaddr));
LOG_TRACE("net_dns_result_next() - Address: %s", ipaddr ? ip_convert_to_string(ipaddr) : "(no more addresses)");
return ipaddr;
}
extern void net_dns_result_free(struct net_dns_result* res)
extern void net_dns_result_free(const struct net_dns_result* res)
{
if (!res)
return;
list_clear(res->addr_list, &hub_free);
list_destroy(res->addr_list);
free_job(res->job);
hub_free(res);
hub_free((struct net_dns_result*) res);
}

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -114,6 +114,6 @@ extern struct ip_addr_encap* net_dns_result_first(const struct net_dns_result*);
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result*);
/// When finished with the results
extern void net_dns_result_free(struct net_dns_result*);
extern void net_dns_result_free(const struct net_dns_result*);
#endif /* HAVE_UHUB_NETWORK_DNS_RESOLVER_H */

View File

@@ -105,6 +105,13 @@ struct ssl_context_handle* net_ssl_context_create()
/* Disable SSLv2 */
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
#ifdef SSL_OP_NO_COMPRESSION
/* Disable compression? */
LOG_TRACE("Disabling SSL compression."); /* "CRIME" attack */
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
SSL_CTX_set_quiet_shutdown(ctx->ssl_ctx, 1);
return (struct ssl_context_handle*) ctx;

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,15 +57,31 @@ size_t timeout_queue_process(struct timeout_queue* t, time_t now)
size_t pos = (size_t) t->last;
size_t events = 0;
struct timeout_evt* evt = 0;
uhub_assert(t->last <= now);
t->last = now;
// We can optimize in case we need to wrap around
// the buffer, so we only do it once
if (MAX(pos, now) - MIN(pos, now) > t->max)
{
// FIXME: Double check this calculation
pos = (now - t->max);
}
for (; pos <= now; pos++)
{
while ((evt = t->events[pos % t->max]))
evt = t->events[pos % t->max];
while (evt)
{
if (evt->timestamp < pos)
{
timeout_queue_remove(t, evt);
evt->callback(evt);
events++;
}
evt = evt->next;
}
}
return events;
}
@@ -85,24 +101,22 @@ size_t timeout_queue_get_next_timeout(struct timeout_queue* t, time_t now)
void timeout_queue_insert(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds)
{
struct timeout_evt* first;
struct timeout_evt* it, *first;
size_t pos = ((t->last + seconds) % t->max);
evt->timestamp = t->last + seconds;
evt->next = 0;
first = t->events[pos];
if (first)
{
uhub_assert(first->timestamp == evt->timestamp);
first->prev->next = evt;
evt->prev = first->prev;
first->prev = evt;
for (it = first; it->next; it = it->next) { }
it->next = evt;
evt->prev = it;
}
else
{
t->events[pos] = evt;
evt->prev = evt;
evt->prev = evt; // point to self.
}
evt->next = 0;
}

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
* Copyright (C) 2007-2013, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -0,0 +1,60 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "plugin_api/handle.h"
#include "util/memory.h"
static plugin_st on_search_result(struct plugin_handle* plugin, struct plugin_user* from, struct plugin_user* to, const char* search_data)
{
if (to->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
static plugin_st on_search(struct plugin_handle* plugin, struct plugin_user* user, const char* search_data)
{
// Registered users are allowed to search.
if (user->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
static plugin_st on_p2p_connect(struct plugin_handle* plugin, struct plugin_user* from, struct plugin_user* to)
{
if (from->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
int plugin_register(struct plugin_handle* plugin, const char* config)
{
PLUGIN_INITIALIZE(plugin, "No guest downloading", "0.1", "This plug-in only allows registered users to search and initiate transfers.");
plugin->ptr = NULL;
plugin->funcs.on_search = on_search;
plugin->funcs.on_search_result = on_search_result;
plugin->funcs.on_p2p_connect = on_p2p_connect;
// plugin->funcs.on_p2p_revconnect = on_p2p_connect;
return 0;
}
int plugin_unregister(struct plugin_handle* plugin)
{
return 0;
}

View File

@@ -127,6 +127,10 @@
*/
#endif
#ifdef __GNU__
#define POSIX_THREAD_SUPPORT
#endif
#define USE_SELECT
#ifndef WINSOCK
#include <sys/select.h>

View File

@@ -30,7 +30,6 @@
enum ADC_client_state
{
ps_none, /* Not connected */
ps_dns, /* looking up name */
ps_conn, /* Connecting... */
ps_conn_ssl, /* SSL handshake */
ps_protocol, /* Have sent HSUP */
@@ -68,7 +67,7 @@ struct ADC_client
struct net_connection* con;
struct net_timer* timer;
struct sockaddr_storage addr;
struct net_dns_job* dns_job;
struct net_connect_handle* connect_job;
struct ADC_client_address address;
char* nick;
char* desc;
@@ -109,7 +108,6 @@ static void ADC_client_debug(struct ADC_client* client, const char* format, ...)
static const char* ADC_client_state_string[] =
{
"ps_none",
"ps_dns",
"ps_conn",
"ps_conn_ssl",
"ps_protocol",
@@ -164,18 +162,12 @@ static void event_callback(struct net_connection* con, int events, void *arg)
switch (client->state)
{
case ps_dns:
break;
case ps_conn:
if (events == NET_EVENT_TIMEOUT)
{
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
return;
}
if (events & NET_EVENT_WRITE)
ADC_client_connect_internal(client);
break;
#ifdef SSL_SUPPORT
@@ -539,11 +531,6 @@ struct ADC_client* ADC_client_create(const char* nickname, const char* descripti
ADC_TRACE;
struct ADC_client* client = (struct ADC_client*) hub_malloc_zero(sizeof(struct ADC_client));
int sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1) return NULL;
client->con = net_con_create();
net_con_initialize(client->con, sd, event_callback, client, 0);
ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname);
@@ -570,40 +557,42 @@ void ADC_client_destroy(struct ADC_client* client)
hub_free(client);
}
static void connect_callback(struct net_connect_handle* handle, enum net_connect_status status, struct net_connection* con, void* ptr)
{
struct ADC_client* client = (struct ADC_client*) ptr;
client->connect_job = NULL;
switch (status)
{
case net_connect_status_ok:
client->con = con;
net_con_reinitialize(client->con, event_callback, client, 0);
ADC_client_on_connected(client);
break;
case net_connect_status_host_not_found:
case net_connect_status_no_address:
case net_connect_status_dns_error:
case net_connect_status_refused:
case net_connect_status_unreachable:
case net_connect_status_timeout:
case net_connect_status_socket_error:
ADC_client_disconnect(client);
break;
}
}
int ADC_client_connect(struct ADC_client* client, const char* address)
{
ADC_TRACE;
if (client->state == ps_none)
{
// Parse address and start name resolving!
if (!ADC_client_parse_address(client, address))
return 0;
return 1;
}
return ADC_client_connect_internal(client);
}
int ADC_client_connect_internal(struct ADC_client* client)
{
int ret;
if (client->state == ps_dns)
{
// Done name resolving!
client->callback(client, ADC_CLIENT_CONNECTING, 0);
ADC_client_set_state(client, ps_conn);
}
ret = net_connect(net_con_get_sd(client->con), (struct sockaddr*) &client->addr, sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
ADC_client_on_connected(client);
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
ADC_client_set_state(client, ps_conn);
}
else
client->connect_job = net_con_connect(client->address.hostname, client->address.port, connect_callback, client);
if (!client->connect_job)
{
ADC_client_on_disconnected(client);
return 0;
@@ -611,6 +600,7 @@ int ADC_client_connect_internal(struct ADC_client* client)
return 1;
}
static void ADC_client_on_connected(struct ADC_client* client)
{
ADC_TRACE;
@@ -674,43 +664,6 @@ void ADC_client_disconnect(struct ADC_client* client)
}
}
int ADC_client_dns_callback(struct net_dns_job* job, const struct net_dns_result* result)
{
struct ADC_client* client = (struct ADC_client*) net_dns_job_get_ptr(job);
struct ip_addr_encap* ipaddr;
LOG_WARN("ADC_client_dns_callback(): result=%p (%d)", result, net_dns_result_size(result));
memset(&client->addr, 0, sizeof(client->addr));
ipaddr = net_dns_result_first(result);
switch (ipaddr->af)
{
case AF_INET:
{
struct sockaddr_in* addr4 = (struct sockaddr_in*) &client->addr;
addr4->sin_family = AF_INET;
addr4->sin_port = htons(client->address.port);
memcpy(&addr4->sin_addr, &ipaddr->internal_ip_data.in, sizeof(struct in_addr));
break;
}
case AF_INET6:
{
struct sockaddr_in6* addr6 = (struct sockaddr_in6*) &client->addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(client->address.port);
memcpy(&addr6->sin6_addr, &ipaddr->internal_ip_data.in6, sizeof(struct in6_addr));
break;
}
default:
LOG_WARN("Unknown ipaddr!");
}
ADC_client_connect_internal(client);
return 1;
}
static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
{
ADC_TRACE;
@@ -753,9 +706,6 @@ static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
client->address.hostname = strndup(hub_address, &split[0] - &hub_address[0]);
client->callback(client, ADC_CLIENT_NAME_LOOKUP, 0);
ADC_client_set_state(client, ps_dns);
client->dns_job = net_dns_gethostbyname(client->address.hostname, AF_UNSPEC, ADC_client_dns_callback, client);
return 1;
}

View File

@@ -21,7 +21,15 @@
#include <locale.h>
#ifndef WIN32
#ifdef SYSTEMD
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>
#else
#include <syslog.h>
#endif
static int use_syslog = 0;
#endif
@@ -83,7 +91,9 @@ void hub_log_initialize(const char* file, int syslog)
if (syslog)
{
use_syslog = 1;
#ifndef SYSTEMD
openlog("uhub", LOG_PID, LOG_USER);
#endif
}
#endif
@@ -132,7 +142,9 @@ void hub_log_shutdown()
if (use_syslog)
{
use_syslog = 0;
#ifndef SYSTEMD
closelog();
#endif
}
#endif
}
@@ -212,7 +224,12 @@ void hub_log(int log_verbosity, const char *format, ...)
case log_fatal: level = LOG_CRIT; break;
case log_error: level = LOG_ERR; break;
case log_warning: level = LOG_WARNING; break;
#ifdef SYSTEMD
case log_user: level = LOG_INFO; break;
#else
case log_user: level = LOG_INFO | LOG_AUTH; break;
#endif
case log_info: level = LOG_INFO; break;
case log_debug: level = LOG_DEBUG; break;
@@ -224,8 +241,13 @@ void hub_log(int log_verbosity, const char *format, ...)
if (level == 0)
return;
#ifdef SYSTEMD
sd_journal_print(level, "%s", logmsg);
#else
level |= (LOG_USER | LOG_DAEMON);
syslog(level, "%s", logmsg);
#endif
}
#endif

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,84 +17,141 @@
*
*/
#if 0
#include <sys/types.h>
#include "uhub.h"
#include "rbtree.h"
#define RED 0
#define BLACK 1
struct rb_node
{
const void* key;
const void* value; /* data */
int color;
struct rb_node* parent;
struct rb_node* left;
struct rb_node* right;
};
struct rb_tree
{
struct rb_node* root;
size_t elements;
rb_tree_alloc alloc;
rb_tree_free free;
rb_tree_compare compare;
};
/* returns the grandparent of a node, if it exits */
static inline struct rb_node* get_grandparent(struct rb_node* n)
{
if (n->parent)
return n->parent->parent;
return 0;
}
static struct rb_node* get_uncle(struct rb_node* n)
{
struct rb_node* gparent = n->parent ? n->parent->parent : 0;
if (gparent)
return (n->parent == gparent->left) ? gparent->right : gparent->left;
return 0;
}
// #define RB_TREE_CHECKS
static struct rb_node* tree_search(struct rb_tree* tree, const void* key)
{
struct rb_node* node = tree->root;
while (node)
{
int res = tree->compare(key, node->key);
if (res < 0) node = node->left;
else if (res > 0) node = node->right;
else return node;
int res = tree->compare(node->key, key);
if (!res)
break;
node = node->link[res < 0];
}
return 0;
return node;
}
static struct rb_node* tree_insert(struct rb_tree* tree, const void* key, const void* value)
static struct rb_node* create_node(struct rb_tree* tree, const void* key, const void* value)
{
struct rb_node* node = tree->root;
struct rb_node* newnode = tree->alloc(sizeof(struct rb_node));
newnode->key = key;
newnode->value = value;
newnode->color = RED;
struct rb_node* node = tree->alloc(sizeof(struct rb_node));
node->key = key;
node->value = value;
node->red = 1;
node->link[0] = 0;
node->link[1] = 0;
return node;
}
static int is_red(struct rb_node* node)
{
return node && node->red;
}
while (node)
{
int res = tree->compare(key, node->key);
if (res < 0) node = node->left;
else if (res > 0) node = node->right;
#ifdef RB_TREE_CHECKS
int rb_tree_check(struct rb_tree* tree, struct rb_node* node)
{
int lh, rh;
if (node == NULL)
return 1;
else
{
/* key already exists in tree */
return node;
struct rb_node *ln = node->link[0];
struct rb_node *rn = node->link[1];
/* Consecutive red links */
if (is_red(node)) {
if (is_red(ln) || is_red(rn))
{
puts("Red violation");
return 0;
}
}
return newnode;
lh = rb_tree_check(tree, ln);
rh = rb_tree_check(tree, rn);
/* Invalid binary search tree - not sorted correctly */
if ((ln && tree->compare(ln->key, node->key) >= 0) || (rn && tree->compare(rn->key, node->key) <= 0))
{
puts("Binary tree violation");
return 0;
}
/* Black height mismatch */
if ( lh != 0 && rh != 0 && lh != rh ) {
puts ( "Black violation" );
return 0;
}
/* Only count black links */
if (lh != 0 && rh != 0)
return is_red(node) ? lh : lh + 1;
else
return 0;
}
}
#endif // RB_TREE_CHECKS
static struct rb_node* rb_tree_rotate_single(struct rb_node* node, int dir)
{
struct rb_node* other = node->link[!dir];
node->link[!dir] = other->link[dir];
other->link[dir] = node;
node->red = 1;
other->red = 0;
return other;
}
static struct rb_node* rb_tree_rotate_double(struct rb_node* node, int dir)
{
node->link[!dir] = rb_tree_rotate_single(node->link[!dir], !dir);
return rb_tree_rotate_single(node, dir);
}
static struct rb_node* rb_tree_insert_r(struct rb_tree* tree, struct rb_node* node, const void* key, const void* value)
{
int res;
if (!node)
return create_node(tree, key, value);
res = tree->compare(node->key, key);
if (!res)
{
puts("Node already exists!");
return NULL;
}
else
{
int dir = res < 0;
node->link[dir] = rb_tree_insert_r(tree, node->link[dir], key, value);
if (is_red(node->link[dir]))
{
if (is_red(node->link[!dir]))
{
/* Case 1 */
node->red = 1;
node->link[0]->red = 0;
node->link[1]->red = 0;
}
else
{
/* Cases 2 & 3 */
if (is_red(node->link[dir]->link[dir]))
node = rb_tree_rotate_single(node, !dir);
else if (is_red(node->link[dir]->link[!dir]))
node = rb_tree_rotate_double(node, !dir);
}
}
}
return node;
}
@@ -102,36 +159,224 @@ struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree
{
struct rb_tree* tree = a(sizeof(struct rb_tree));
tree->compare = compare;
tree->alloc = a;
tree->free = f;
tree->alloc = a ? a : hub_malloc;
tree->free = f ? f : hub_free;
tree->root = NULL;
tree->elements = 0;
tree->iterator.node = NULL;
tree->iterator.stack = list_create();
return tree;
}
void rb_tree_destroy(struct rb_tree* tree)
{
rb_tree_free f = tree->free;
f(tree);
list_destroy(tree->iterator.stack);
tree->free(tree);
}
void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* value)
int rb_tree_insert(struct rb_tree* tree, const void* key, const void* value)
{
struct rb_node* node = tree_insert(tree, key, value);
if (node)
return (void*) node->value;
struct rb_node* node;
if (tree_search(tree, key))
return 0;
node = rb_tree_insert_r(tree, tree->root, key, value);
tree->root = node;
tree->root->red = 0;
tree->elements++;
#ifdef RB_TREE_CHECKS
rb_tree_check(tree, node);
#endif
return 1;
}
void* rb_tree_remove(struct rb_tree* tree, const void* key)
{
void null_node_free(struct rb_node* n) { }
int rb_tree_remove(struct rb_tree* tree, const void* key)
{
return rb_tree_remove_node(tree, key, &null_node_free);
}
int rb_tree_remove_node(struct rb_tree* tree, const void* key, rb_tree_free_node freecb)
{
struct rb_node head = {0}; /* False tree root */
struct rb_node *q, *p, *g; /* Helpers */
struct rb_node *f = NULL; /* Found item */
int dir = 1;
if (!tree->root)
return 0;
/* Set up helpers */
q = &head;
g = p = NULL;
q->link[1] = tree->root;
/* Search and push a red down */
while (q->link[dir])
{
int last = dir;
int res;
/* Update helpers */
g = p, p = q;
q = q->link[dir];
res = tree->compare(q->key, key);
dir = res < 0;
/* Save found node */
if (!res)
f = q;
/* Push the red node down */
if (!is_red(q) && !is_red(q->link[dir]))
{
if (is_red(q->link[!dir]))
p = p->link[last] = rb_tree_rotate_single(q, dir);
else if (!is_red(q->link[!dir]))
{
struct rb_node* s = p->link[!last];
if (s)
{
if (!is_red(s->link[!last]) && !is_red (s->link[last]))
{
/* Color flip */
p->red = 0;
s->red = 1;
q->red = 1;
}
else
{
int dir2 = g->link[1] == p;
if (is_red(s->link[last]))
g->link[dir2] = rb_tree_rotate_double(p, last);
else if (is_red(s->link[!last]))
g->link[dir2] = rb_tree_rotate_single(p, last);
/* Ensure correct coloring */
q->red = g->link[dir2]->red = 1;
g->link[dir2]->link[0]->red = 0;
g->link[dir2]->link[1]->red = 0;
}
}
}
}
}
/* Replace and remove if found */
if (f)
{
freecb(f);
f->key = q->key;
f->value = q->value;
p->link[p->link[1] == q] = q->link[q->link[0] == NULL];
tree->free(q);
tree->elements--;
}
/* Update root and make it black */
tree->root = head.link[1];
if (tree->root != NULL)
tree->root->red = 0;
#ifdef RB_TREE_CHECKS
rb_tree_check(tree, tree->root);
#endif
return f != NULL;
}
void* rb_tree_get(struct rb_tree* tree, const void* key)
{
struct rb_node* node = tree_search(tree, key);
if (node)
return node->value;
return (void*) node->value;
return 0;
}
#endif
size_t rb_tree_size(struct rb_tree* tree)
{
return tree->elements;
}
static void push(struct rb_tree* tree, struct rb_node* n)
{
list_append(tree->iterator.stack, n);
}
static struct rb_node* pop(struct rb_tree* tree)
{
struct rb_node* n = list_get_last(tree->iterator.stack);
if (n)
list_remove(tree->iterator.stack, n);
return n;
}
static struct rb_node* rb_it_set(struct rb_tree* tree, struct rb_node* n)
{
tree->iterator.node = n;
return n;
}
static void null_free(void* ptr) { }
struct rb_node* rb_tree_first(struct rb_tree* tree)
{
struct rb_node* n = tree->root;
list_clear(tree->iterator.stack, &null_free);
while (n->link[0])
{
push(tree, n);
n = n->link[0];
}
return rb_it_set(tree, n);
};
static struct rb_node* rb_tree_traverse(struct rb_tree* tree, int dir)
{
struct rb_node* n = tree->iterator.node;
struct rb_node* p; /* parent */
if (n->link[dir])
{
push(tree, n);
n = n->link[dir];
while (n->link[!dir])
{
list_append(tree->iterator.stack, n);
n = n->link[!dir];
}
return rb_it_set(tree, n);
}
// Need to walk upwards to the parent node.
p = pop(tree);
if (p)
{
// walk up in opposite direction
if (p->link[!dir] == n)
return rb_it_set(tree, p);
// walk up in hte current direction
while (p->link[dir] == n)
{
n = p;
p = pop(tree);
if (!p)
return rb_it_set(tree, NULL);
}
return rb_it_set(tree, p);
}
return rb_it_set(tree, NULL);
}
struct rb_node* rb_tree_next(struct rb_tree* tree)
{
return rb_tree_traverse(tree, 1);
}
struct rb_node* rb_tree_prev(struct rb_tree* tree)
{
return rb_tree_traverse(tree, 0);
}

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,19 +20,122 @@
#ifndef HAVE_UHUB_RED_BLACK_TREE_H
#define HAVE_UHUB_RED_BLACK_TREE_H
struct rb_tree;
struct rb_node
{
const void* key;
const void* value; /* data */
int red;
struct rb_node* link[2];
};
typedef int (*rb_tree_compare)(const void* a, const void* b);
typedef void* (*rb_tree_alloc)(size_t);
typedef void (*rb_tree_free)(void*);
typedef void (*rb_tree_free_node)(struct rb_node*);
struct rb_iterator
{
struct rb_node* node; // current node.
struct linked_list* stack; // stack from the top -- needed since we don't have parent pointers.
};
struct rb_tree
{
struct rb_node* root;
size_t elements;
rb_tree_alloc alloc;
rb_tree_free free;
rb_tree_compare compare;
struct rb_iterator iterator;
};
extern struct rb_tree* rb_tree_create(rb_tree_compare, rb_tree_alloc, rb_tree_free);
/**
* Create a tree.
*
* @param compare Comparison function
* @param alloc Allocator (if NULL then hub_malloc() is used)
* @param dealloc Deallocator (if NULL then hub_free() is used)
* @return a tree handle.
*/
extern struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc alloc, rb_tree_free dealloc);
/**
* Deletes the tree and all the nodes.
* But not the content inside the nodes.
*/
extern void rb_tree_destroy(struct rb_tree*);
extern void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* data);
extern void* rb_tree_remove(struct rb_tree* tree, const void* key);
/**
* Insert a key into the tree, returns 1 if successful,
* or 0 if the key already existed.
*/
extern int rb_tree_insert(struct rb_tree* tree, const void* key, const void* data);
/**
* Remove a key from the tree.
* Returns 1 if the node was removed, or 0 if it was not removed (i.e. not found!)
*
* NOTE: the content of the node is not freed if it needs to be then use rb_tree_remove_node
* where you can specify a callback cleanup function.
*/
extern int rb_tree_remove(struct rb_tree* tree, const void* key);
/**
* Remove the node, but call the free callback before the node is removed.
* This is useful in cases where you need to deallocate the key and/or value from the node.
* Returns 1 if the node was removed, or 0 if not found.
*/
extern int rb_tree_remove_node(struct rb_tree* tree, const void* key, rb_tree_free_node free);
/**
* Returns NULL if the key was not found in the tree.
*/
extern void* rb_tree_get(struct rb_tree* tree, const void* key);
/**
* Returns the number of elements inside the tree.
*/
extern size_t rb_tree_size(struct rb_tree* tree);
/**
* Returns the first node in the tree.
* (leftmost, or lowest value in sorted order).
*
* Example:
*
* <code>
* struct rb_node* it;
* for (it = rb_tree_first(tree); it; it = rb_tree_next())
* {
* void* key = rb_iterator_key(it);
* void* value = rb_iterator_value(it);
* }
* </code>
*/
extern struct rb_node* rb_tree_first(struct rb_tree* tree);
/**
* Points the iterator at the next node.
* If the next node is NULL then the iterator becomes NULL too.
*/
extern struct rb_node* rb_tree_next(struct rb_tree* tree);
extern struct rb_node* rb_tree_prev(struct rb_tree* tree);
/**
* Returnst the key of the node pointed to by the iterator.
* If this iterator is the same as rb_tree_end() then NULL is returned.
*/
extern void* rb_iterator_key(struct rb_iterator* it);
/**
* Returnst the value of the node pointed to by the iterator.
* If this iterator is the same as rb_tree_end() then the behavior is undefined.
*/
extern void* rb_iterator_value(struct rb_iterator* it);
#endif /* HAVE_UHUB_RED_BLACK_TREE_H */

43
tools/uhub-adc-redirector.py Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python
"""
A simple ADC redirector service.
"""
import SocketServer
# The target hub we want to redirect clients to
redirect_uri = "adcs://adcs.uhub.org:1511"
# A message to be sent to users while they are being redirected.
message = "This hub has been permanently moved."
# The chat name of the message.
bot_name = "Redirector"
# The local address and port to bind the redirector to.
bind_addr = "0.0.0.0"
bind_port = 1411
class AdcRedirector(SocketServer.BaseRequestHandler):
def escape(self, str):
modified = str.replace("\\", "\\\\").replace(" ", "\\s").replace("\n", "\\n")
return modified;
def handle(self):
supports = False;
while True:
data = self.request.recv(1024)
if (data.startswith("HSUP") and not supports):
self.request.sendall("ISUP ADBASE ADTIGR\nISID AAAX\nIINF CT32 NI%(botname)s VEuhub-adc-redirector/0.1\n" % { "address": redirect_uri, "botname": self.escape(bot_name), "message": self.escape(message) })
supports = True
elif (data.startswith("BINF") and supports):
self.request.sendall("IMSG %(message)s\nIQUI AAAX RD%(address)s\n" % {"message": self.escape(message), "address": redirect_uri })
break
else:
break
if __name__ == "__main__":
server = SocketServer.TCPServer((bind_addr, bind_port), AdcRedirector)
server.allow_reuse_address = True
server.serve_forever()

30
tools/uhub-nmdc-redirector.py Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
"""
A simple NMDC to ADC redirector service.
"""
import SocketServer
# The target hub we want to redirect clients to
redirect_uri = "adcs://adcs.uhub.org:1511"
# A message to be sent to users while they are being redirected.
message = "This hub has been permanently moved."
# The chat name of the message.
bot_name = "Redirector"
# The local address and port to bind the redirector to.
bind_addr = "0.0.0.0"
bind_port = 1411
class NmdcRedirector(SocketServer.BaseRequestHandler):
def setup(self):
self.request.sendall("<%(botname)s> %(message)s|$ForceMove %(address)s|" % { "address": redirect_uri, "botname": bot_name, "message": message })
return False
if __name__ == "__main__":
server = SocketServer.TCPServer((bind_addr, bind_port), NmdcRedirector)
server.allow_reuse_address = True
server.serve_forever()