Compare commits
11 Commits
async_dns_
...
0.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af0f293a6 | ||
|
|
a492f30950 | ||
|
|
a43953bc0d | ||
|
|
594801df46 | ||
|
|
3dcbb63a31 | ||
|
|
5d6184961b | ||
|
|
b17e88573e | ||
|
|
2d2ccc0039 | ||
|
|
0a2f9c4b79 | ||
|
|
ae62c35cb9 | ||
|
|
2ec2e73f16 |
8
AUTHORS
8
AUTHORS
@@ -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
|
||||
|
||||
@@ -67,6 +67,7 @@ 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_library(mod_example MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_example.c)
|
||||
add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c)
|
||||
@@ -75,6 +76,7 @@ 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)
|
||||
add_library(mod_no_guest_downloads MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_no_guest_downloads.c)
|
||||
|
||||
if (SQLITE_SUPPORT)
|
||||
add_library(mod_auth_sqlite MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_sqlite.c)
|
||||
@@ -88,6 +90,7 @@ endif()
|
||||
|
||||
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()
|
||||
@@ -99,14 +102,17 @@ set_target_properties(
|
||||
mod_auth_simple
|
||||
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(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_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)
|
||||
@@ -119,6 +125,7 @@ if(UNIX)
|
||||
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 +164,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()
|
||||
@@ -179,7 +187,7 @@ 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 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)
|
||||
|
||||
15
ChangeLog
15
ChangeLog
@@ -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
372
autotest/exotic
Executable 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");
|
||||
}
|
||||
'; }
|
||||
|
||||
1032
autotest/test.c
Normal file
1032
autotest/test.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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) \
|
||||
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;
|
||||
|
||||
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; \
|
||||
} 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);
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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
144
autotest/test_rbtree.tcc
Normal 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;
|
||||
});
|
||||
|
||||
|
||||
@@ -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
4
autotest/update.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
./exotic *.tcc > test.c
|
||||
|
||||
@@ -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;
|
||||
|
||||
60
src/plugins/mod_no_guest_downloads.c
Normal file
60
src/plugins/mod_no_guest_downloads.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
while (node)
|
||||
static int is_red(struct rb_node* node)
|
||||
{
|
||||
return node && node->red;
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
int res = tree->compare(key, node->key);
|
||||
if (res < 0) node = node->left;
|
||||
else if (res > 0) node = node->right;
|
||||
else
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
/* key already exists in tree */
|
||||
return node;
|
||||
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 newnode;
|
||||
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;
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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,18 +20,121 @@
|
||||
#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);
|
||||
extern void* rb_tree_get(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 */
|
||||
|
||||
Reference in New Issue
Block a user