Compare commits
25 Commits
async_dns_
...
link_suppo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51fba8a7a1 | ||
|
|
a7898779cb | ||
|
|
f6f7c7a3a4 | ||
|
|
1fbde2b0fd | ||
|
|
92b65a0e14 | ||
|
|
4d438e1e90 | ||
|
|
4f3c71234b | ||
|
|
fdaadccb99 | ||
|
|
41251f8d32 | ||
|
|
3b18ae251e | ||
|
|
b452488431 | ||
|
|
143b68588a | ||
|
|
5f2b7bc069 | ||
|
|
ce68c446d1 | ||
|
|
6af0f293a6 | ||
|
|
a492f30950 | ||
|
|
a43953bc0d | ||
|
|
594801df46 | ||
|
|
3dcbb63a31 | ||
|
|
5d6184961b | ||
|
|
b17e88573e | ||
|
|
2d2ccc0039 | ||
|
|
0a2f9c4b79 | ||
|
|
ae62c35cb9 | ||
|
|
2ec2e73f16 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,6 +14,7 @@ uhub-admin
|
|||||||
adcrush
|
adcrush
|
||||||
uhub
|
uhub
|
||||||
build-stamp
|
build-stamp
|
||||||
|
build.ninja
|
||||||
debian/files
|
debian/files
|
||||||
debian/uhub.debhelper.log
|
debian/uhub.debhelper.log
|
||||||
debian/uhub.postinst.debhelper
|
debian/uhub.postinst.debhelper
|
||||||
@@ -22,3 +23,4 @@ debian/uhub.prerm.debhelper
|
|||||||
debian/uhub.substvars
|
debian/uhub.substvars
|
||||||
uhub-passwd
|
uhub-passwd
|
||||||
src/version.h
|
src/version.h
|
||||||
|
|
||||||
|
|||||||
8
AUTHORS
8
AUTHORS
@@ -3,7 +3,9 @@ Authors of uhub
|
|||||||
|
|
||||||
Jan Vidar Krey, Design and implementation
|
Jan Vidar Krey, Design and implementation
|
||||||
E_zombie, Centos/RedHat customization scripts and heavy load testing
|
E_zombie, Centos/RedHat customization scripts and heavy load testing
|
||||||
FleetCommand, Hub topic
|
FleetCommand, Hub topic plugin code
|
||||||
MiMic, Implemented user commands
|
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
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
## Copyright (C) 2007-2012, Jan Vidar Krey <janvidar@extatic.org>
|
## 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)
|
project (uhub NONE)
|
||||||
enable_language(C)
|
enable_language(C)
|
||||||
@@ -13,15 +13,17 @@ set (UHUB_VERSION_MINOR 4)
|
|||||||
set (UHUB_VERSION_PATCH 1)
|
set (UHUB_VERSION_PATCH 1)
|
||||||
|
|
||||||
set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
|
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(RELEASE "Release build, debug build if disabled" ON)
|
||||||
option(LINK_SUPPORT "Allow hub linking" OFF)
|
option(LINK_SUPPORT "Allow hub linking" OFF)
|
||||||
option(SSL_SUPPORT "Enable SSL support" ON)
|
option(SSL_SUPPORT "Enable SSL support" ON)
|
||||||
option(USE_OPENSSL "Use OpenSSL's 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)
|
option(ADC_STRESS "Enable the stress tester client" OFF)
|
||||||
|
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
|
find_package(Sqlite3)
|
||||||
|
|
||||||
if (SSL_SUPPORT)
|
if (SSL_SUPPORT)
|
||||||
if (USE_OPENSSL)
|
if (USE_OPENSSL)
|
||||||
@@ -34,11 +36,22 @@ if (SSL_SUPPORT)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (LINK_SUPPORT)
|
||||||
|
add_definitions(-DLINK_SUPPORT)
|
||||||
|
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)
|
if (MSVC)
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}")
|
include_directories("${PROJECT_SOURCE_DIR}")
|
||||||
|
include_directories(${SQLITE3_INCLUDE_DIRS})
|
||||||
|
|
||||||
file (GLOB uhub_SOURCES ${PROJECT_SOURCE_DIR}/core/*.c)
|
file (GLOB uhub_SOURCES ${PROJECT_SOURCE_DIR}/core/*.c)
|
||||||
list (REMOVE_ITEM uhub_SOURCES
|
list (REMOVE_ITEM uhub_SOURCES
|
||||||
@@ -67,6 +80,8 @@ add_dependencies(adc utils)
|
|||||||
add_dependencies(network utils)
|
add_dependencies(network utils)
|
||||||
|
|
||||||
add_executable(uhub ${PROJECT_SOURCE_DIR}/core/main.c ${uhub_SOURCES} )
|
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_example MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_example.c)
|
||||||
add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c)
|
add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c)
|
||||||
@@ -75,19 +90,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_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_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_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)
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(uhub ws2_32)
|
target_link_libraries(uhub ws2_32)
|
||||||
|
target_link_libraries(test ws2_32)
|
||||||
target_link_libraries(mod_logging ws2_32)
|
target_link_libraries(mod_logging ws2_32)
|
||||||
target_link_libraries(mod_welcome ws2_32)
|
target_link_libraries(mod_welcome ws2_32)
|
||||||
endif()
|
endif()
|
||||||
@@ -97,16 +105,22 @@ set_target_properties(
|
|||||||
mod_welcome
|
mod_welcome
|
||||||
mod_logging
|
mod_logging
|
||||||
mod_auth_simple
|
mod_auth_simple
|
||||||
|
mod_auth_sqlite
|
||||||
mod_chat_history
|
mod_chat_history
|
||||||
mod_chat_only
|
mod_chat_only
|
||||||
|
mod_no_guest_downloads
|
||||||
mod_topic
|
mod_topic
|
||||||
PROPERTIES PREFIX "")
|
PROPERTIES PREFIX "")
|
||||||
|
|
||||||
target_link_libraries(uhub ${CMAKE_DL_LIBS} adc network utils)
|
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_example utils)
|
||||||
target_link_libraries(mod_welcome utils)
|
target_link_libraries(mod_welcome utils)
|
||||||
target_link_libraries(mod_auth_simple 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_chat_history utils)
|
||||||
|
target_link_libraries(mod_no_guest_downloads utils)
|
||||||
target_link_libraries(mod_chat_only utils)
|
target_link_libraries(mod_chat_only utils)
|
||||||
target_link_libraries(mod_logging utils)
|
target_link_libraries(mod_logging utils)
|
||||||
target_link_libraries(mod_topic utils)
|
target_link_libraries(mod_topic utils)
|
||||||
@@ -114,11 +128,13 @@ target_link_libraries(utils network)
|
|||||||
target_link_libraries(mod_welcome network)
|
target_link_libraries(mod_welcome network)
|
||||||
target_link_libraries(mod_logging network)
|
target_link_libraries(mod_logging network)
|
||||||
|
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
add_library(adcclient STATIC ${adcclient_SOURCES})
|
add_library(adcclient STATIC ${adcclient_SOURCES})
|
||||||
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c)
|
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c)
|
||||||
target_link_libraries(uhub-admin adcclient adc network utils pthread)
|
target_link_libraries(uhub-admin adcclient adc network utils pthread)
|
||||||
target_link_libraries(uhub pthread)
|
target_link_libraries(uhub pthread)
|
||||||
|
target_link_libraries(test pthread)
|
||||||
|
|
||||||
if (ADC_STRESS)
|
if (ADC_STRESS)
|
||||||
add_executable(adcrush ${PROJECT_SOURCE_DIR}/tools/adcrush.c ${adcclient_SOURCES})
|
add_executable(adcrush ${PROJECT_SOURCE_DIR}/tools/adcrush.c ${adcclient_SOURCES})
|
||||||
@@ -157,6 +173,7 @@ endif()
|
|||||||
|
|
||||||
if(SSL_SUPPORT)
|
if(SSL_SUPPORT)
|
||||||
target_link_libraries(uhub ${SSL_LIBS})
|
target_link_libraries(uhub ${SSL_LIBS})
|
||||||
|
target_link_libraries(test ${SSL_LIBS})
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
target_link_libraries(uhub-admin ${SSL_LIBS})
|
target_link_libraries(uhub-admin ${SSL_LIBS})
|
||||||
endif()
|
endif()
|
||||||
@@ -167,24 +184,33 @@ if(SSL_SUPPORT)
|
|||||||
endif()
|
endif()
|
||||||
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")
|
configure_file ("${PROJECT_SOURCE_DIR}/version.h.in" "${PROJECT_SOURCE_DIR}/version.h")
|
||||||
|
|
||||||
mark_as_advanced(FORCE CMAKE_BUILD_TYPE)
|
mark_as_advanced(FORCE CMAKE_BUILD_TYPE)
|
||||||
if (RELEASE)
|
if (RELEASE)
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
add_definitions(-DNDEBUG)
|
||||||
else()
|
else()
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
# add_definitions(-DDEBUG)
|
add_definitions(-DDEBUG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
install( TARGETS uhub RUNTIME DESTINATION bin )
|
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 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 )
|
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()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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:
|
0.4.0:
|
||||||
- Cleaned up code generator for config file parsing.
|
- Cleaned up code generator for config file parsing.
|
||||||
- Merge pull request #5 from yorhel/master
|
- 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()
|
static void inf_create_hub()
|
||||||
{
|
{
|
||||||
|
net_initialize();
|
||||||
inf_hub = (struct hub_info*) hub_malloc_zero(sizeof(struct hub_info));
|
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 = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
|
||||||
inf_hub->users->list = list_create();
|
inf_hub->users->list = list_create();
|
||||||
@@ -35,6 +36,7 @@ static void inf_destroy_hub()
|
|||||||
hub_free(inf_hub->acl);
|
hub_free(inf_hub->acl);
|
||||||
hub_free(inf_hub->config);
|
hub_free(inf_hub->config);
|
||||||
hub_free(inf_hub);
|
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 */
|
/* FIXME: MEMORY LEAK - Need to fix hub_handle_info_login */
|
||||||
#define CHECK_INF(MSG, EXPECT) \
|
#define CHECK_INF(MSG, EXPECT) \
|
||||||
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
|
do { \
|
||||||
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
|
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
|
||||||
adc_msg_free(msg); \
|
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
|
||||||
if (ok == EXPECT) \
|
adc_msg_free(msg); \
|
||||||
user_set_info(inf_user, 0); \
|
if (ok == EXPECT) \
|
||||||
return 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); });
|
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_09, { CHECK_INF("BINF AAAB NIabc NIdef IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", status_msg_inf_error_nick_multiple); });
|
||||||
EXO_TEST(inf_nick_10, {
|
EXO_TEST(inf_nick_10, {
|
||||||
const char* line = "BINF AAAB IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n";
|
const char* line = "BINF AAAB IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n";
|
||||||
|
int ok;
|
||||||
char nick[10];
|
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;
|
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);
|
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);
|
adc_msg_free(msg);
|
||||||
if (ok != status_msg_inf_error_nick_not_utf8)
|
if (ok != status_msg_inf_error_nick_not_utf8)
|
||||||
printf("Expected %d, got %d\n", status_msg_inf_error_nick_not_utf8, ok);
|
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, {
|
EXO_TEST(check_ban_ipv6_1, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_ipv6_2, {
|
EXO_TEST(check_ban_ipv6_2, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_ipv6_3, {
|
EXO_TEST(check_ban_ipv6_3, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_ipv6_4, {
|
EXO_TEST(check_ban_ipv6_4, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_ipv6_5, {
|
EXO_TEST(check_ban_ipv6_5, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return !ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_ipv6_6, {
|
EXO_TEST(check_ban_ipv6_6, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return !ip_in_range(&addr, &ban6);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(check_ban_afmix_1, {
|
EXO_TEST(check_ban_afmix_1, {
|
||||||
|
struct ip_addr_encap addr;
|
||||||
if (!ipv6) return 1;
|
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);
|
return !ip_in_range(&addr, &ban4);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -610,8 +617,10 @@ EXO_TEST(ip_range_3, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(ip_range_4, {
|
EXO_TEST(ip_range_4, {
|
||||||
struct ip_range range1; memset(&range1, 0, sizeof(range1));
|
struct ip_range range1;
|
||||||
struct ip_range range2; memset(&range2, 0, sizeof(range2));
|
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;
|
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, {
|
EXO_TEST(adc_message_add_arg_1, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_add_argument(msg, "XXwtf?");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_add_arg_2, {
|
EXO_TEST(adc_message_add_arg_2, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_add_named_argument(msg, "XX", "wtf?");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_remove_arg_1, {
|
EXO_TEST(adc_message_remove_arg_1, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "AA");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_remove_arg_2, {
|
EXO_TEST(adc_message_remove_arg_2, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "BB");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_remove_arg_3, {
|
EXO_TEST(adc_message_remove_arg_3, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "CC");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_remove_arg_4, {
|
EXO_TEST(adc_message_remove_arg_4, {
|
||||||
/* this ensures we can remove the last element also */
|
/* 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));
|
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string3, strlen(test_string3));
|
||||||
adc_msg_remove_named_argument(msg, "AW");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_replace_arg_1, {
|
EXO_TEST(adc_message_replace_arg_1, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "AA");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_replace_arg_2, {
|
EXO_TEST(adc_message_replace_arg_2, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "BB");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_replace_arg_3, {
|
EXO_TEST(adc_message_replace_arg_3, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_remove_named_argument(msg, "CC");
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_get_arg_1, {
|
EXO_TEST(adc_message_get_arg_1, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
char* c = adc_msg_get_argument(msg, 0);
|
char* c = adc_msg_get_argument(msg, 0);
|
||||||
int ok = strcmp(c, "AAfoo") == 0;
|
ok = strcmp(c, "AAfoo") == 0;
|
||||||
adc_msg_free(msg);
|
adc_msg_free(msg);
|
||||||
hub_free(c);
|
hub_free(c);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_get_arg_2, {
|
EXO_TEST(adc_message_get_arg_2, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
char* c = adc_msg_get_argument(msg, 1);
|
char* c = adc_msg_get_argument(msg, 1);
|
||||||
int ok = strcmp(c, "BBbar") == 0;
|
ok = strcmp(c, "BBbar") == 0;
|
||||||
adc_msg_free(msg);
|
adc_msg_free(msg);
|
||||||
hub_free(c);
|
hub_free(c);
|
||||||
return ok;
|
return ok;
|
||||||
@@ -340,28 +351,31 @@ EXO_TEST(adc_message_has_named_arg_3, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_has_named_arg_4, {
|
EXO_TEST(adc_message_has_named_arg_4, {
|
||||||
|
int n;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_add_argument(msg, "XXwtf?");
|
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);
|
adc_msg_free(msg);
|
||||||
return n == 1;
|
return n == 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_has_named_arg_5, {
|
EXO_TEST(adc_message_has_named_arg_5, {
|
||||||
|
int n;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_add_argument(msg, "XXone");
|
adc_msg_add_argument(msg, "XXone");
|
||||||
adc_msg_add_argument(msg, "XXtwo");
|
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);
|
adc_msg_free(msg);
|
||||||
return n == 2;
|
return n == 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_has_named_arg_6, {
|
EXO_TEST(adc_message_has_named_arg_6, {
|
||||||
|
int n;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_add_argument(msg, "XXone");
|
adc_msg_add_argument(msg, "XXone");
|
||||||
adc_msg_add_argument(msg, "XXtwo");
|
adc_msg_add_argument(msg, "XXtwo");
|
||||||
adc_msg_add_argument(msg, "XXthree");
|
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);
|
adc_msg_free(msg);
|
||||||
return n == 3;
|
return n == 3;
|
||||||
});
|
});
|
||||||
@@ -374,63 +388,70 @@ EXO_TEST(adc_message_has_named_arg_7, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_1, {
|
EXO_TEST(adc_message_terminate_1, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create("IINF AAfoo BBbar CCwhat");
|
struct adc_message* msg = adc_msg_create("IINF AAfoo BBbar CCwhat");
|
||||||
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_2, {
|
EXO_TEST(adc_message_terminate_2, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_unterminate(msg);
|
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_3, {
|
EXO_TEST(adc_message_terminate_3, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_unterminate(msg);
|
adc_msg_unterminate(msg);
|
||||||
adc_msg_terminate(msg);
|
adc_msg_terminate(msg);
|
||||||
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_4, {
|
EXO_TEST(adc_message_terminate_4, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_unterminate(msg);
|
adc_msg_unterminate(msg);
|
||||||
adc_msg_terminate(msg);
|
adc_msg_terminate(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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_5, {
|
EXO_TEST(adc_message_terminate_5, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_terminate(msg);
|
adc_msg_terminate(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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_terminate_6, {
|
EXO_TEST(adc_message_terminate_6, {
|
||||||
|
int ok;
|
||||||
struct adc_message* msg = adc_msg_create(test_string1);
|
struct adc_message* msg = adc_msg_create(test_string1);
|
||||||
adc_msg_unterminate(msg);
|
adc_msg_unterminate(msg);
|
||||||
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);
|
adc_msg_free(msg);
|
||||||
return ok;
|
return ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXO_TEST(adc_message_escape_1, {
|
EXO_TEST(adc_message_escape_1, {
|
||||||
|
int ok;
|
||||||
char* s = adc_msg_escape(test_string1);
|
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);
|
hub_free(s);
|
||||||
return ok;
|
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_1, { return is_valid_utf8("abcdefghijklmnopqrstuvwxyz"); });
|
||||||
EXO_TEST(utf8_valid_2, { 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_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} ); });
|
static const char test_utf_seq_1[] = { 0x65, 0x00 }; // valid
|
||||||
EXO_TEST(utf8_valid_7, { return !is_valid_utf8( (char[]) { 0xC2, 0x24, 0x00} ); });
|
static const char test_utf_seq_2[] = { 0xD8, 0x00 }; // invalid
|
||||||
EXO_TEST(utf8_valid_8, { return is_valid_utf8( (char[]) { 0xC2, 0xA2, 0x00} ); });
|
static const char test_utf_seq_3[] = { 0x24, 0x00 }; // valid
|
||||||
EXO_TEST(utf8_valid_9, { return is_valid_utf8( (char[]) { 0xE2, 0x82, 0xAC, 0x00} ); });
|
static const char test_utf_seq_4[] = { 0xC2, 0x24, 0x00}; // invalid
|
||||||
EXO_TEST(utf8_valid_10, { return !is_valid_utf8( (char[]) { 0xC2, 0x32, 0x00} ); });
|
static const char test_utf_seq_5[] = { 0xC2, 0xA2, 0x00}; // valid
|
||||||
EXO_TEST(utf8_valid_11, { return !is_valid_utf8( (char[]) { 0xE2, 0x82, 0x32, 0x00} ); });
|
static const char test_utf_seq_6[] = { 0xE2, 0x82, 0xAC, 0x00}; // valid
|
||||||
EXO_TEST(utf8_valid_12, { return !is_valid_utf8( (char[]) { 0xE2, 0x32, 0x82, 0x00} ); });
|
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)
|
static int match_str(const char* str1, char* str2)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
for (i = 0; i < strlen(str2); i++)
|
for (i = 0; i < strlen(str2); i++)
|
||||||
if (str2[i] == '_')
|
if (str2[i] == '_')
|
||||||
str2[i] = ' ';
|
str2[i] = ' ';
|
||||||
else if (str2[i] == '|')
|
else if (str2[i] == '|')
|
||||||
str2[i] = '\t';
|
str2[i] = '\t';
|
||||||
|
|
||||||
int ret = strcmp(str1, str2);
|
ret = strcmp(str1, str2);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, "\n Mismatch: \"%s\" != \"%s\"\n", str1, str2);
|
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) {
|
static int compare(const char* str, const char* ref) {
|
||||||
size_t i, max;
|
size_t i, max;
|
||||||
|
int pass;
|
||||||
struct linked_list* compare = list_create();
|
struct linked_list* compare = list_create();
|
||||||
SETUP(tokens, str);
|
SETUP(tokens, str);
|
||||||
split_string(ref, " ", compare, 0);
|
split_string(ref, " ", compare, 0);
|
||||||
int pass = cfg_token_count(tokens) == list_size(compare);
|
pass = cfg_token_count(tokens) == list_size(compare);
|
||||||
if (pass) {
|
if (pass) {
|
||||||
max = cfg_token_count(tokens);
|
max = cfg_token_count(tokens);
|
||||||
for (i = 0; i < max; i++) {
|
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
|
||||||
|
|
||||||
77
cmake/Modules/FindSqlite3.cmake
Normal file
77
cmake/Modules/FindSqlite3.cmake
Normal 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 )
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -34,6 +34,7 @@ typedef uint32_t fourcc_t;
|
|||||||
|
|
||||||
/* default welcome protocol support message, as sent by this server */
|
/* default welcome protocol support message, as sent by this server */
|
||||||
#define ADC_PROTO_SUPPORT "ADBASE ADTIGR ADPING ADUCMD"
|
#define ADC_PROTO_SUPPORT "ADBASE ADTIGR ADPING ADUCMD"
|
||||||
|
#define ADC_PROTO_LINK_SUPPORT "ADTIGR ADLINK"
|
||||||
|
|
||||||
/* Server sent commands */
|
/* Server sent commands */
|
||||||
#define ADC_CMD_ISID FOURCC('I','S','I','D')
|
#define ADC_CMD_ISID FOURCC('I','S','I','D')
|
||||||
@@ -101,6 +102,12 @@ typedef uint32_t fourcc_t;
|
|||||||
#define ADC_CMD_HCMD FOURCC('H','C','M','D')
|
#define ADC_CMD_HCMD FOURCC('H','C','M','D')
|
||||||
#define ADC_CMD_ICMD FOURCC('I','C','M','D')
|
#define ADC_CMD_ICMD FOURCC('I','C','M','D')
|
||||||
|
|
||||||
|
/* Link commands */
|
||||||
|
#define ADC_CMD_LSUP FOURCC('L','S','U','P') /* Link support handshake */
|
||||||
|
#define ADC_CMD_LINF FOURCC('L','I','N','F') /* Hub link info */
|
||||||
|
#define ADC_CMD_LGPA FOURCC('L','G','P','A') /* Hub link get password */
|
||||||
|
#define ADC_CMD_LPAS FOURCC('L','P','A','S') /* Hub link password */
|
||||||
|
#define ADC_CMD_LSTA FOURCC('L','S','T','A') /* Hub link status */
|
||||||
|
|
||||||
#define ADC_INF_FLAG_IPV4_ADDR "I4" /* ipv4 address */
|
#define ADC_INF_FLAG_IPV4_ADDR "I4" /* ipv4 address */
|
||||||
#define ADC_INF_FLAG_IPV6_ADDR "I6" /* ipv6 address */
|
#define ADC_INF_FLAG_IPV6_ADDR "I6" /* ipv6 address */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -178,6 +178,7 @@ int adc_msg_get_arg_offset(struct adc_message* msg)
|
|||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
case 'H':
|
case 'H':
|
||||||
|
case 'L':
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
@@ -383,8 +384,9 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
|
|||||||
ok = 0;
|
ok = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I': /* Hub to client */
|
||||||
case 'H':
|
case 'H': /* Clien to hub */
|
||||||
|
case 'L': /* hub to hub Link */
|
||||||
ok = (length > 3);
|
ok = (length > 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -787,6 +789,16 @@ int adc_msg_add_argument(struct adc_message* cmd, const char* string)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int adc_msg_add_argument_string(struct adc_message* cmd, const char* string)
|
||||||
|
{
|
||||||
|
char* arg = adc_msg_escape(string);
|
||||||
|
int ret;
|
||||||
|
if (!arg) return -1;
|
||||||
|
ret = adc_msg_add_argument(cmd, arg);
|
||||||
|
hub_free(arg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char* adc_msg_get_argument(struct adc_message* cmd, int offset)
|
char* adc_msg_get_argument(struct adc_message* cmd, int offset)
|
||||||
{
|
{
|
||||||
@@ -868,21 +880,21 @@ int adc_msg_get_argument_index(struct adc_message* cmd, const char prefix[2])
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int adc_msg_escape_length(const char* str)
|
size_t adc_msg_escape_length(const char* str)
|
||||||
{
|
{
|
||||||
int add = 0;
|
size_t add = 0;
|
||||||
int n = 0;
|
size_t n = 0;
|
||||||
for (; str[n]; n++)
|
for (; str[n]; n++)
|
||||||
if (str[n] == ' ' || str[n] == '\n' || str[n] == '\\') add++;
|
if (str[n] == ' ' || str[n] == '\n' || str[n] == '\\') add++;
|
||||||
return n + add;
|
return n + add;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int adc_msg_unescape_length(const char* str)
|
size_t adc_msg_unescape_length(const char* str)
|
||||||
{
|
{
|
||||||
int add = 0;
|
size_t add = 0;
|
||||||
int n = 0;
|
size_t n = 0;
|
||||||
int escape = 0;
|
size_t escape = 0;
|
||||||
for (; str[n]; n++)
|
for (; str[n]; n++)
|
||||||
{
|
{
|
||||||
if (escape)
|
if (escape)
|
||||||
@@ -998,3 +1010,20 @@ char* adc_msg_escape(const char* string)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum msg_type adc_msg_get_type(const struct adc_message* msg)
|
||||||
|
{
|
||||||
|
switch (msg->cache[0])
|
||||||
|
{
|
||||||
|
case 'B': return msg_type_client_broadcast;
|
||||||
|
case 'C': return msg_type_client_to_client;
|
||||||
|
case 'D': return msg_type_client_direct;
|
||||||
|
case 'E': return msg_type_client_echo;
|
||||||
|
case 'F': return msg_type_client_feature;
|
||||||
|
case 'H': return msg_type_client_to_hub;
|
||||||
|
case 'I': return msg_type_hub_to_client;
|
||||||
|
case 'L': return msg_type_link_to_link;
|
||||||
|
case 'U': return msg_type_hub_to_client_udp;
|
||||||
|
}
|
||||||
|
return msg_type_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -43,6 +43,20 @@ enum msg_status_level
|
|||||||
status_level_fatal = 2, /* Fatal error (disconnect) */
|
status_level_fatal = 2, /* Fatal error (disconnect) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum msg_type
|
||||||
|
{
|
||||||
|
msg_type_unknown = 0,
|
||||||
|
msg_type_client_broadcast = 'B',
|
||||||
|
msg_type_client_to_client = 'C',
|
||||||
|
msg_type_client_direct = 'D',
|
||||||
|
msg_type_client_echo = 'E',
|
||||||
|
msg_type_client_feature = 'F',
|
||||||
|
msg_type_client_to_hub = 'H',
|
||||||
|
msg_type_hub_to_client = 'I',
|
||||||
|
msg_type_link_to_link = 'L',
|
||||||
|
msg_type_hub_to_client_udp = 'U',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the reference counter for an ADC message struct.
|
* Increase the reference counter for an ADC message struct.
|
||||||
* NOTE: Always use the returned value, and not the passed value, as
|
* NOTE: Always use the returned value, and not the passed value, as
|
||||||
@@ -171,6 +185,13 @@ 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);
|
extern int adc_msg_add_argument(struct adc_message* cmd, const char* string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a string argumnent.
|
||||||
|
* The string will automatcally be 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
|
* Append a named argument
|
||||||
*
|
*
|
||||||
@@ -216,6 +237,12 @@ extern int adc_msg_unescape_to_target(const char* string, char* target, size_t t
|
|||||||
*/
|
*/
|
||||||
extern char* adc_msg_escape(const char* string);
|
extern char* adc_msg_escape(const char* string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the length str would be after escaping.
|
||||||
|
* Does not include any NULL terminator.
|
||||||
|
*/
|
||||||
|
size_t adc_msg_escape_length(const char* str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will ensure a newline is at the end of the command.
|
* This will ensure a newline is at the end of the command.
|
||||||
*/
|
*/
|
||||||
@@ -234,4 +261,6 @@ void adc_msg_unterminate(struct adc_message* cmd);
|
|||||||
*/
|
*/
|
||||||
int adc_msg_get_arg_offset(struct adc_message* msg);
|
int adc_msg_get_arg_offset(struct adc_message* msg);
|
||||||
|
|
||||||
|
enum msg_type adc_msg_get_type(const struct adc_message* msg);
|
||||||
|
|
||||||
#endif /* HAVE_UHUB_COMMAND_H */
|
#endif /* HAVE_UHUB_COMMAND_H */
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ static int config_parse_line(char* line, int line_count, void* ptr_data)
|
|||||||
data = strip_white_space(data);
|
data = strip_white_space(data);
|
||||||
data = strip_off_quotes(data);
|
data = strip_off_quotes(data);
|
||||||
|
|
||||||
if (!*key || !*data)
|
if (!*key /*|| !*data*/)
|
||||||
{
|
{
|
||||||
LOG_FATAL("Configuration parse error on line %d", line_count);
|
LOG_FATAL("Configuration parse error on line %d", line_count);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -165,6 +165,36 @@
|
|||||||
<since>0.3.2</since>
|
<since>0.3.2</since>
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
|
<option name="hub_link_enabled" type="boolean" default="0">
|
||||||
|
<short>Allow other hubs to link to this hub</short>
|
||||||
|
<description><![CDATA[
|
||||||
|
This allows multiple hubs to link to this hub so
|
||||||
|
that users on the different hubs appear as being on one hub.
|
||||||
|
This is useful for distributing or load balancing large hubs.
|
||||||
|
]]></description>
|
||||||
|
<since>0.5.0</since>
|
||||||
|
<ifdef>LINK_SUPPORT</ifdef>
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option name="hub_link_secret" type="string" default="">
|
||||||
|
<short>A secret token required to accept hub linking</short>
|
||||||
|
<description><![CDATA[
|
||||||
|
This should be a secret token needed to authorize hubs
|
||||||
|
linking into this one.
|
||||||
|
]]></description>
|
||||||
|
<since>0.5.0</since>
|
||||||
|
<ifdef>LINK_SUPPORT</ifdef>
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option name="hub_link_connect" type="string" default="">
|
||||||
|
<short>Connect this to hub to another hub</short>
|
||||||
|
<description><![CDATA[
|
||||||
|
The other hub must allow links to be established.
|
||||||
|
Example: uhub://host:port
|
||||||
|
]]></description>
|
||||||
|
<since>0.5.0</since>
|
||||||
|
<ifdef>LINK_SUPPORT</ifdef>
|
||||||
|
</option>
|
||||||
|
|
||||||
<option name="max_recv_buffer" type="int" default="4096" advanced="true" >
|
<option name="max_recv_buffer" type="int" default="4096" advanced="true" >
|
||||||
<check min="1024" max="1048576" />
|
<check min="1024" max="1048576" />
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ void config_defaults(struct hub_config* config)
|
|||||||
config->hub_name = hub_strdup("uhub");
|
config->hub_name = hub_strdup("uhub");
|
||||||
config->hub_description = hub_strdup("no description");
|
config->hub_description = hub_strdup("no description");
|
||||||
config->redirect_addr = hub_strdup("");
|
config->redirect_addr = hub_strdup("");
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
config->hub_link_enabled = 0;
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
config->hub_link_secret = hub_strdup("");
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
config->hub_link_connect = hub_strdup("");
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
config->max_recv_buffer = 4096;
|
config->max_recv_buffer = 4096;
|
||||||
config->max_send_buffer = 131072;
|
config->max_send_buffer = 131072;
|
||||||
config->max_send_buffer_soft = 98304;
|
config->max_send_buffer_soft = 98304;
|
||||||
@@ -245,6 +254,42 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!strcmp(key, "hub_link_enabled"))
|
||||||
|
{
|
||||||
|
if (!apply_boolean(key, data, &config->hub_link_enabled))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Configuration parse error on line %d", line_count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!strcmp(key, "hub_link_secret"))
|
||||||
|
{
|
||||||
|
if (!apply_string(key, data, &config->hub_link_secret, (char*) ""))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Configuration parse error on line %d", line_count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!strcmp(key, "hub_link_connect"))
|
||||||
|
{
|
||||||
|
if (!apply_string(key, data, &config->hub_link_connect, (char*) ""))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Configuration parse error on line %d", line_count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
if (!strcmp(key, "max_recv_buffer"))
|
if (!strcmp(key, "max_recv_buffer"))
|
||||||
{
|
{
|
||||||
min = 1024;
|
min = 1024;
|
||||||
@@ -943,6 +988,14 @@ void free_config(struct hub_config* config)
|
|||||||
|
|
||||||
hub_free(config->redirect_addr);
|
hub_free(config->redirect_addr);
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
hub_free(config->hub_link_secret);
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
hub_free(config->hub_link_connect);
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
hub_free(config->tls_require_redirect_addr);
|
hub_free(config->tls_require_redirect_addr);
|
||||||
|
|
||||||
hub_free(config->tls_certificate);
|
hub_free(config->tls_certificate);
|
||||||
@@ -1074,6 +1127,21 @@ void dump_config(struct hub_config* config, int ignore_defaults)
|
|||||||
if (!ignore_defaults || strcmp(config->redirect_addr, "") != 0)
|
if (!ignore_defaults || strcmp(config->redirect_addr, "") != 0)
|
||||||
fprintf(stdout, "redirect_addr = \"%s\"\n", config->redirect_addr);
|
fprintf(stdout, "redirect_addr = \"%s\"\n", config->redirect_addr);
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!ignore_defaults || config->hub_link_enabled != 0)
|
||||||
|
fprintf(stdout, "hub_link_enabled = %s\n", config->hub_link_enabled ? "yes" : "no");
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!ignore_defaults || strcmp(config->hub_link_secret, "") != 0)
|
||||||
|
fprintf(stdout, "hub_link_secret = \"%s\"\n", config->hub_link_secret);
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (!ignore_defaults || strcmp(config->hub_link_connect, "") != 0)
|
||||||
|
fprintf(stdout, "hub_link_connect = \"%s\"\n", config->hub_link_connect);
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
|
||||||
if (!ignore_defaults || config->max_recv_buffer != 4096)
|
if (!ignore_defaults || config->max_recv_buffer != 4096)
|
||||||
fprintf(stdout, "max_recv_buffer = %d\n", config->max_recv_buffer);
|
fprintf(stdout, "max_recv_buffer = %d\n", config->max_recv_buffer);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ struct hub_config
|
|||||||
char* hub_name; /*<<< Name of hub (default: "uhub") */
|
char* hub_name; /*<<< Name of hub (default: "uhub") */
|
||||||
char* hub_description; /*<<< Short hub description, topic or subject. (default: "no description") */
|
char* hub_description; /*<<< Short hub description, topic or subject. (default: "no description") */
|
||||||
char* redirect_addr; /*<<< A common hub redirect address. (default: "") */
|
char* redirect_addr; /*<<< A common hub redirect address. (default: "") */
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
int hub_link_enabled; /*<<< Allow other hubs to link to this hub (default: 0) */
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
char* hub_link_secret; /*<<< A secret token required to accept hub linking (default: "") */
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
char* hub_link_connect; /*<<< Connect this to hub to another hub (default: "") */
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
int max_recv_buffer; /*<<< Max read buffer before parse, per user (default: 4096) */
|
int max_recv_buffer; /*<<< Max read buffer before parse, per user (default: 4096) */
|
||||||
int max_send_buffer; /*<<< Max send buffer before disconnect, per user (default: 131072) */
|
int max_send_buffer; /*<<< Max send buffer before disconnect, per user (default: 131072) */
|
||||||
int max_send_buffer_soft; /*<<< Max send buffer before message drops, per user (default: 98304) */
|
int max_send_buffer_soft; /*<<< Max send buffer before message drops, per user (default: 98304) */
|
||||||
|
|||||||
@@ -787,6 +787,13 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (config->hub_link_enabled)
|
||||||
|
{
|
||||||
|
LOG_INFO("Hub linking support enabled");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
hub->config = config;
|
hub->config = config;
|
||||||
hub->users = NULL;
|
hub->users = NULL;
|
||||||
|
|
||||||
@@ -834,6 +841,15 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
|||||||
|
|
||||||
// Start the hub command sub-system
|
// Start the hub command sub-system
|
||||||
hub->commands = command_initialize(hub);
|
hub->commands = command_initialize(hub);
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
if (*config->hub_link_connect)
|
||||||
|
{
|
||||||
|
link_connect_uri(hub, config->hub_link_connect);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
return hub;
|
return hub;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,23 +913,14 @@ void hub_plugins_unload(struct hub_info* hub)
|
|||||||
|
|
||||||
void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
|
void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
|
||||||
{
|
{
|
||||||
char* tmp;
|
|
||||||
char* server = adc_msg_escape(PRODUCT_STRING); /* FIXME: OOM */
|
|
||||||
|
|
||||||
hub->acl = acl;
|
hub->acl = acl;
|
||||||
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15);
|
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15);
|
||||||
if (hub->command_info)
|
if (hub->command_info)
|
||||||
{
|
{
|
||||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
|
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
|
||||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, server);
|
adc_msg_add_named_argument_string(hub->command_info, ADC_INF_FLAG_USER_AGENT, PRODUCT_STRING);
|
||||||
|
adc_msg_add_named_argument_string(hub->command_info, ADC_INF_FLAG_NICK, hub->config->hub_name);
|
||||||
tmp = adc_msg_escape(hub->config->hub_name);
|
adc_msg_add_named_argument_string(hub->command_info, ADC_INF_FLAG_DESCRIPTION, hub->config->hub_description);
|
||||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_NICK, tmp);
|
|
||||||
hub_free(tmp);
|
|
||||||
|
|
||||||
tmp = adc_msg_escape(hub->config->hub_description);
|
|
||||||
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp);
|
|
||||||
hub_free(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT));
|
hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT));
|
||||||
@@ -922,16 +929,14 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
|
|||||||
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
|
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 100 + strlen(server));
|
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 100 + adc_msg_escape_length(PRODUCT_STRING));
|
||||||
if (hub->command_banner)
|
if (hub->command_banner)
|
||||||
{
|
{
|
||||||
if (hub->config->show_banner_sys_info)
|
|
||||||
tmp = adc_msg_escape("Powered by " PRODUCT_STRING " on " OPSYS "/" CPUINFO);
|
|
||||||
else
|
|
||||||
tmp = adc_msg_escape("Powered by " PRODUCT_STRING);
|
|
||||||
adc_msg_add_argument(hub->command_banner, "000");
|
adc_msg_add_argument(hub->command_banner, "000");
|
||||||
adc_msg_add_argument(hub->command_banner, tmp);
|
if (hub->config->show_banner_sys_info)
|
||||||
hub_free(tmp);
|
adc_msg_add_argument_string(hub->command_banner, "Powered by " PRODUCT_STRING " on " OPSYS "/" CPUINFO);
|
||||||
|
else
|
||||||
|
adc_msg_add_argument_string(hub->command_banner, "Powered by " PRODUCT_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hub_plugins_load(hub) < 0)
|
if (hub_plugins_load(hub) < 0)
|
||||||
@@ -942,7 +947,6 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
|
|||||||
else
|
else
|
||||||
|
|
||||||
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
|
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
|
||||||
hub_free(server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ struct hub_info
|
|||||||
struct command_base* commands; /* Hub command handler */
|
struct command_base* commands; /* Hub command handler */
|
||||||
struct uhub_plugins* plugins; /* Plug-ins loaded for this hub instance. */
|
struct uhub_plugins* plugins; /* Plug-ins loaded for this hub instance. */
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
struct linked_list* hub_links; /* Other hubs linked to this hub */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SSL_SUPPORT
|
#ifdef SSL_SUPPORT
|
||||||
struct ssl_context_handle* ctx;
|
struct ssl_context_handle* ctx;
|
||||||
#endif /* SSL_SUPPORT */
|
#endif /* SSL_SUPPORT */
|
||||||
|
|||||||
@@ -49,6 +49,34 @@ void ioq_recv_destroy(struct ioq_recv* q)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IOQ_RECV_FLAGS_PREALLOC 1
|
||||||
|
#define IOQ_RECV_FLAGS_FULL 2
|
||||||
|
|
||||||
|
enum ioq_recv_status ioq_recv_read(struct ioq_recv* q, struct net_connection* con)
|
||||||
|
{
|
||||||
|
static char buf[MAX_RECV_BUF];
|
||||||
|
size_t buf_size = ioq_recv_get(q, buf, MAX_RECV_BUF);
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
if (buf_size >= MAX_RECV_BUF)
|
||||||
|
return ioq_recv_full;
|
||||||
|
|
||||||
|
size = net_con_recv(con, buf + buf_size, MAX_RECV_BUF - buf_size);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
buf_size += size;
|
||||||
|
if (size < 0)
|
||||||
|
return ioq_recv_error;
|
||||||
|
if (size == 0)
|
||||||
|
return ioq_recv_later;
|
||||||
|
|
||||||
|
ioq_recv_set(q, buf, buf_size);
|
||||||
|
return ioq_recv_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t ioq_recv_get(struct ioq_recv* q, void* buf, size_t bufsize)
|
size_t ioq_recv_get(struct ioq_recv* q, void* buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
uhub_assert(bufsize >= q->size);
|
uhub_assert(bufsize >= q->size);
|
||||||
@@ -88,6 +116,21 @@ size_t ioq_recv_set(struct ioq_recv* q, void* buf, size_t bufsize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ioq_recv_consume(struct ioq_recv* q, size_t bytes)
|
||||||
|
{
|
||||||
|
size_t newsize;
|
||||||
|
void* ptr;
|
||||||
|
|
||||||
|
if (!q || bytes > q->size) return 0;
|
||||||
|
|
||||||
|
newsize = (q->size - bytes);
|
||||||
|
memmove(q->buf, q->buf + bytes, newsize);
|
||||||
|
ptr = hub_realloc(q->buf, newsize);
|
||||||
|
q->buf = ptr;
|
||||||
|
q->size = newsize;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
struct ioq_send* ioq_send_create()
|
struct ioq_send* ioq_send_create()
|
||||||
{
|
{
|
||||||
struct ioq_send* q = hub_malloc_zero(sizeof(struct ioq_send));
|
struct ioq_send* q = hub_malloc_zero(sizeof(struct ioq_send));
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ struct ioq_recv
|
|||||||
{
|
{
|
||||||
char* buf;
|
char* buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
// int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,5 +103,26 @@ extern size_t ioq_recv_set(struct ioq_recv*, void* buf, size_t bufsize);
|
|||||||
extern int ioq_recv_is_empty(struct ioq_recv* buf);
|
extern int ioq_recv_is_empty(struct ioq_recv* buf);
|
||||||
|
|
||||||
|
|
||||||
|
enum ioq_recv_status
|
||||||
|
{
|
||||||
|
ioq_recv_ok = 0, // read data OK
|
||||||
|
ioq_recv_later = 1, // all OK, but call again later (no change)
|
||||||
|
ioq_recv_full = 2, // all OK, but the buffer is full
|
||||||
|
ioq_recv_error = 3, // error (connection is not working)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive from connection into buffer.
|
||||||
|
*/
|
||||||
|
extern enum ioq_recv_status ioq_recv_read(struct ioq_recv* q, struct net_connection* con);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume 'bytes' bytes.
|
||||||
|
* 'bytes' must be <= q->size
|
||||||
|
*
|
||||||
|
* @return 1 on success, or 0 on error (only if q == NULL or bytes is > q->size).
|
||||||
|
*/
|
||||||
|
extern int ioq_recv_consume(struct ioq_recv* q, size_t bytes);
|
||||||
|
|
||||||
|
|
||||||
#endif /* HAVE_UHUB_IO_QUEUE_H */
|
#endif /* HAVE_UHUB_IO_QUEUE_H */
|
||||||
|
|||||||
508
src/core/link.c
Normal file
508
src/core/link.c
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
* uhub - A tiny ADC p2p connection hub
|
||||||
|
* 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
|
||||||
|
* 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 "uhub.h"
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
static int link_send_support(struct hub_link* link);
|
||||||
|
|
||||||
|
static void link_net_event(struct net_connection* con, int event, void *arg)
|
||||||
|
{
|
||||||
|
LOG_INFO("link_net_event(), event=%d", event);
|
||||||
|
struct hub_link* link = (struct hub_link*) arg;
|
||||||
|
struct hub_info* hub = link->hub;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (event == NET_EVENT_TIMEOUT)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Hub link timeout!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event & NET_EVENT_READ)
|
||||||
|
{
|
||||||
|
ret = link_handle_read(link);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
link_disconnect(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event & NET_EVENT_WRITE)
|
||||||
|
{
|
||||||
|
ret = link_handle_write(link);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
link_disconnect(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void link_disconnect(struct hub_link* link)
|
||||||
|
{
|
||||||
|
if (link->connection)
|
||||||
|
net_con_close(link->connection);
|
||||||
|
link->connection = NULL;
|
||||||
|
|
||||||
|
ioq_send_destroy(link->send_queue);
|
||||||
|
ioq_recv_destroy(link->recv_queue);
|
||||||
|
link->send_queue = NULL;
|
||||||
|
link->recv_queue = NULL;
|
||||||
|
|
||||||
|
// FIXME: Notify hub and disconnect users!
|
||||||
|
|
||||||
|
hub_free(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hub_link* link_create_internal(struct hub_info* hub)
|
||||||
|
{
|
||||||
|
struct hub_link* link = NULL;
|
||||||
|
|
||||||
|
LOG_DEBUG("link_create_internal(), hub=%p");
|
||||||
|
link = (struct hub_link*) hub_malloc_zero(sizeof(struct hub_link));
|
||||||
|
if (link == NULL)
|
||||||
|
return NULL; /* OOM */
|
||||||
|
|
||||||
|
link->send_queue = ioq_send_create();
|
||||||
|
link->recv_queue = ioq_recv_create();
|
||||||
|
|
||||||
|
link->hub = hub;
|
||||||
|
link->state = state_protocol;
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hub_link* link_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr)
|
||||||
|
{
|
||||||
|
struct hub_link* link = link_create_internal(hub);
|
||||||
|
link->connection = con;
|
||||||
|
net_con_reinitialize(link->connection, link_net_event, link, NET_EVENT_READ);
|
||||||
|
link->mode = link_mode_server;
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void link_connect_callback(struct net_connect_handle* handle, enum net_connect_status status, struct net_connection* con, void* ptr)
|
||||||
|
{
|
||||||
|
struct hub_link* link = (struct hub_link*) ptr;
|
||||||
|
link->connect_job = NULL;
|
||||||
|
|
||||||
|
LOG_DEBUG("link_connect_callback()");
|
||||||
|
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case net_connect_status_ok:
|
||||||
|
link->connection = con;
|
||||||
|
net_con_reinitialize(link->connection, link_net_event, link, NET_EVENT_READ);
|
||||||
|
// FIXME: send handshake here
|
||||||
|
link_send_support(link);
|
||||||
|
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:
|
||||||
|
// FIXME: Unable to connect - start timer and re-try connection establishment!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct link_address
|
||||||
|
{
|
||||||
|
char host[256];
|
||||||
|
uint16_t port;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int link_parse_address(const char* arg, struct link_address* addr)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
char* split;
|
||||||
|
|
||||||
|
memset(addr, 0, sizeof(struct link_address));
|
||||||
|
|
||||||
|
/* Split hostname and port (if possible) */
|
||||||
|
split = strrchr(arg, ':');
|
||||||
|
if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Ensure port number is valid */
|
||||||
|
port = strtol(split+1, NULL, 10);
|
||||||
|
if (port <= 0 || port > 65535)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(addr->host, arg, &split[0] - &arg[0]);
|
||||||
|
addr->port = port;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hub_link* link_connect_uri(struct hub_info* hub, const char* address)
|
||||||
|
{
|
||||||
|
struct link_address link_address;
|
||||||
|
if (!link_parse_address(address, &link_address))
|
||||||
|
{
|
||||||
|
LOG_INFO("Invalid master hub link address");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return link_connect(hub, link_address.host, link_address.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hub_link* link_connect(struct hub_info* hub, const char* address, uint16_t port)
|
||||||
|
{
|
||||||
|
struct hub_link* link = link_create_internal(hub);
|
||||||
|
|
||||||
|
LOG_DEBUG("Connecting to master link at %s:%d...", address, port);
|
||||||
|
|
||||||
|
link->mode = link_mode_client;
|
||||||
|
link->connect_job = net_con_connect(address, port, link_connect_callback, link);
|
||||||
|
if (!link->connect_job)
|
||||||
|
{
|
||||||
|
// FIXME: Immediate failure!
|
||||||
|
LOG_DEBUG("Error connecting to master hub link.");
|
||||||
|
link_disconnect(link);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_net_io_want_read(struct hub_link* link)
|
||||||
|
{
|
||||||
|
net_con_update(link->connection, NET_EVENT_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_net_io_want_write(struct hub_link* link)
|
||||||
|
{
|
||||||
|
net_con_update(link->connection, NET_EVENT_READ | NET_EVENT_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int link_handle_write(struct hub_link* link)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
while (ioq_send_get_bytes(link->send_queue))
|
||||||
|
{
|
||||||
|
ret = ioq_send_send(link->send_queue, link->connection);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return -1; // FIXME! Extract socket error!
|
||||||
|
|
||||||
|
if (ioq_send_get_bytes(link->send_queue))
|
||||||
|
link_net_io_want_write(link);
|
||||||
|
else
|
||||||
|
link_net_io_want_read(link);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int link_send_message(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_SENDQ
|
||||||
|
char* data = strndup(msg->cache, msg->length-1);
|
||||||
|
LOG_PROTO("[link] send %p: \"%s\"", link, data);
|
||||||
|
free(data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!link->connection)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uhub_assert(msg->cache && *msg->cache);
|
||||||
|
|
||||||
|
if (ioq_send_is_empty(link->send_queue) /*&& !user_flag_get(user, flag_pipeline)*/)
|
||||||
|
{
|
||||||
|
/* Perform oportunistic write */
|
||||||
|
ioq_send_add(link->send_queue, msg);
|
||||||
|
link_handle_write(link);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if (check_send_queue(hub, user, msg) >= 0)
|
||||||
|
// {
|
||||||
|
ioq_send_add(link->send_queue, msg);
|
||||||
|
// if (!user_flag_get(user, flag_pipeline))
|
||||||
|
link_net_io_want_write(link);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_send_support(struct hub_link* link)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct adc_message* msg = adc_msg_construct(ADC_CMD_LSUP, 6 + strlen(ADC_PROTO_LINK_SUPPORT));
|
||||||
|
adc_msg_add_argument(msg, ADC_PROTO_LINK_SUPPORT);
|
||||||
|
ret = link_send_message(link, msg);
|
||||||
|
adc_msg_free(msg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_send_welcome(struct hub_link* link)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct adc_message* info = adc_msg_construct(ADC_CMD_LINF, 128);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
adc_msg_add_named_argument(info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
|
||||||
|
adc_msg_add_named_argument_string(info, ADC_INF_FLAG_USER_AGENT, PRODUCT_STRING);
|
||||||
|
adc_msg_add_named_argument_string(info, ADC_INF_FLAG_NICK, link->hub->config->hub_name);
|
||||||
|
adc_msg_add_named_argument_string(info, ADC_INF_FLAG_DESCRIPTION, link->hub->config->hub_description);
|
||||||
|
|
||||||
|
ret = link_send_message(link, info);
|
||||||
|
|
||||||
|
link->state = state_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_send_auth_response(struct hub_link* link, const char* challenge)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct adc_message* msg = adc_msg_construct(ADC_CMD_LPAS, 128);
|
||||||
|
|
||||||
|
// FIXME: Solve challenge.
|
||||||
|
|
||||||
|
ret = link_send_message(link, msg);
|
||||||
|
adc_msg_free(msg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_send_auth_request(struct hub_link* link)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct adc_message* msg = adc_msg_construct(ADC_CMD_LGPA, 128);
|
||||||
|
|
||||||
|
// FIXME: Create challenge.
|
||||||
|
char buf[64];
|
||||||
|
uint64_t tiger_res[3];
|
||||||
|
static char tiger_buf[MAX_CID_LEN+1];
|
||||||
|
|
||||||
|
LOG_DEBUG("link_send_auth_request");
|
||||||
|
|
||||||
|
// FIXME: Generate a better nonce scheme.
|
||||||
|
snprintf(buf, 64, "%p%d", link, (int) net_con_get_sd(link->connection));
|
||||||
|
|
||||||
|
tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res);
|
||||||
|
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
|
||||||
|
tiger_buf[MAX_CID_LEN] = 0;
|
||||||
|
|
||||||
|
// Add nonce to message
|
||||||
|
adc_msg_add_argument(msg, (const char*) tiger_buf);
|
||||||
|
ret = link_send_message(link, msg);
|
||||||
|
adc_msg_free(msg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_support(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
LOG_DEBUG("link_handle_support");
|
||||||
|
|
||||||
|
if (link->mode == link_mode_server)
|
||||||
|
{
|
||||||
|
if (link->state == state_protocol)
|
||||||
|
{
|
||||||
|
ret = link_send_support(link);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = link_send_auth_request(link);
|
||||||
|
link->state = state_verify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_auth_request(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
char* challenge;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
LOG_DEBUG("link_handle_auth_request");
|
||||||
|
|
||||||
|
if (link->state == state_verify)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (link->mode == link_mode_client)
|
||||||
|
{
|
||||||
|
challenge = adc_msg_get_argument(msg, 0);
|
||||||
|
ret = link_send_auth_response(link, challenge);
|
||||||
|
hub_free(challenge);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_auth_response(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
|
||||||
|
LOG_DEBUG("link_handle_auth_response. link_state=%d", (int) link->state);
|
||||||
|
|
||||||
|
if (link->state != state_verify)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
LOG_DEBUG("State is not verify!");
|
||||||
|
|
||||||
|
if (link->mode == link_mode_server)
|
||||||
|
{
|
||||||
|
// Check authentication data
|
||||||
|
// FIXME: Can involve plug-ins at this point.
|
||||||
|
return link_send_welcome(link);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Ignoring auth response - We're client mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_link_info(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("link_handle_link_info");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_status(struct hub_link* link, struct adc_message* msg)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("link_handle_status");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_handle_message(struct hub_link* link, const char* message, size_t length)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct adc_message* cmd = 0;
|
||||||
|
|
||||||
|
LOG_INFO("link_handle_message(): %s (%d)", message, (int) length);
|
||||||
|
|
||||||
|
// FIXME: is this needed?
|
||||||
|
if (link->state == state_cleanup || link->state == state_disconnected)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cmd = adc_msg_parse(message, length);
|
||||||
|
if (!cmd)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Unable to parse hub-link message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (
|
||||||
|
|
||||||
|
switch (cmd->cmd)
|
||||||
|
{
|
||||||
|
case ADC_CMD_LSUP:
|
||||||
|
ret = link_handle_support(link, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADC_CMD_LPAS:
|
||||||
|
ret = link_handle_auth_response(link, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADC_CMD_LGPA:
|
||||||
|
ret = link_handle_auth_request(link, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADC_CMD_LINF:
|
||||||
|
ret = link_handle_link_info(link, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADC_CMD_LSTA:
|
||||||
|
ret = link_handle_status(link, cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_msg_free(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int link_read_message(struct hub_link* link)
|
||||||
|
{
|
||||||
|
char* lastPos = 0;
|
||||||
|
char* pos = 0;
|
||||||
|
char* start = link->recv_queue->buf;
|
||||||
|
size_t remaining = link->recv_queue->size;
|
||||||
|
|
||||||
|
while ((pos = memchr(start, '\n', remaining)))
|
||||||
|
{
|
||||||
|
lastPos = pos+1;
|
||||||
|
pos[0] = '\0';
|
||||||
|
|
||||||
|
if (link->flags & 1)
|
||||||
|
{
|
||||||
|
/* FIXME Unset maxbuf flag */
|
||||||
|
link->flags = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (link_handle_message(link, start, (pos - start)) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos[0] = '\n'; /* FIXME: not needed */
|
||||||
|
pos ++;
|
||||||
|
remaining -= (pos - start);
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioq_recv_consume(link->recv_queue, (start - link->recv_queue->buf));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_handle_read(struct hub_link* link)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (ioq_recv_read(link->recv_queue, link->connection))
|
||||||
|
{
|
||||||
|
case ioq_recv_ok:
|
||||||
|
if (link_read_message(link) < 0)
|
||||||
|
{
|
||||||
|
// FIXME: propagate protocol error?
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Parse messages then call again
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ioq_recv_later:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case ioq_recv_full:
|
||||||
|
link->flags = 1; // FIXME: MAXBUF
|
||||||
|
ioq_recv_set(link->recv_queue, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ioq_recv_error:
|
||||||
|
return -1; // FIXME: it would be good to signal type of socket error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
70
src/core/link.h
Normal file
70
src/core/link.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* uhub - A tiny ADC p2p connection hub
|
||||||
|
* 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
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HAVE_UHUB_LINK_H
|
||||||
|
#define HAVE_UHUB_LINK_H
|
||||||
|
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
|
||||||
|
struct hub_link
|
||||||
|
{
|
||||||
|
char name[MAX_NICK_LEN+1]; /** The name of the linked hub */
|
||||||
|
char user_agent[MAX_UA_LEN+1]; /** The user agent of the linked hub */
|
||||||
|
char address[256]; /** The official address of the linked hub */
|
||||||
|
enum link_mode { link_mode_client, link_mode_server } mode;
|
||||||
|
enum user_state state;
|
||||||
|
struct ioq_send* send_queue;
|
||||||
|
struct ioq_recv* recv_queue;
|
||||||
|
struct net_connection* connection; /** Connection data */
|
||||||
|
struct net_connect_handle* connect_job; /** Only used when establishing a connection in client mode */
|
||||||
|
struct hub_info* hub;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a link from an accepted connection (act as a link server).
|
||||||
|
*/
|
||||||
|
extern struct hub_link* link_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect this hub to an upstream server (act as a link client).
|
||||||
|
*/
|
||||||
|
extern struct hub_link* link_connect(struct hub_info* hub, const char* address, uint16_t port);
|
||||||
|
extern struct hub_link* link_connect_uri(struct hub_info* hub, const char* address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect a link connection.
|
||||||
|
*/
|
||||||
|
extern void link_disconnect(struct hub_link*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from link connection and process messages.
|
||||||
|
* @return 0 on success, and a negative value otherwise
|
||||||
|
*/
|
||||||
|
extern int link_handle_read(struct hub_link* link);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write queued messages to the link.
|
||||||
|
* @return 0 on success, and a negative value otherwise.
|
||||||
|
*/
|
||||||
|
extern int link_handle_write(struct hub_link* link);
|
||||||
|
|
||||||
|
#endif // LINK_SUPPORT
|
||||||
|
|
||||||
|
#endif /* HAVE_UHUB_LINK_H */
|
||||||
@@ -19,6 +19,10 @@
|
|||||||
|
|
||||||
#include "uhub.h"
|
#include "uhub.h"
|
||||||
|
|
||||||
|
#ifdef SYSTEMD
|
||||||
|
#include <systemd/sd-daemon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static int arg_verbose = 5;
|
static int arg_verbose = 5;
|
||||||
static int arg_fork = 0;
|
static int arg_fork = 0;
|
||||||
static int arg_check_config = 0;
|
static int arg_check_config = 0;
|
||||||
@@ -121,6 +125,10 @@ int main_loop()
|
|||||||
hub_set_log_verbosity(arg_verbose);
|
hub_set_log_verbosity(arg_verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
LOG_INFO("Debug messages enabled");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (read_config(arg_config, &configuration, !arg_have_config) == -1)
|
if (read_config(arg_config, &configuration, !arg_have_config) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -145,7 +153,16 @@ int main_loop()
|
|||||||
}
|
}
|
||||||
#if !defined(WIN32)
|
#if !defined(WIN32)
|
||||||
setup_signal_handlers(hub);
|
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);
|
hub_set_variables(hub, &acl);
|
||||||
@@ -216,13 +233,17 @@ void print_usage(char* program)
|
|||||||
" -q Quiet mode - no output\n"
|
" -q Quiet mode - no output\n"
|
||||||
" -f Fork to background\n"
|
" -f Fork to background\n"
|
||||||
" -l <file> Log messages to given file (default: stderr)\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 <file> Specify configuration file (default: " SERVER_CONFIG ")\n"
|
||||||
" -C Check configuration and return\n"
|
" -C Check configuration and return\n"
|
||||||
" -s Show configuration parameters\n"
|
" -s Show configuration parameters\n"
|
||||||
" -S Show configuration parameters, but ignore defaults\n"
|
" -S Show configuration parameters, but ignore defaults\n"
|
||||||
" -h This message\n"
|
" -h This message\n"
|
||||||
#ifndef WIN32
|
#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"
|
" -u <user> Run as given user\n"
|
||||||
" -g <group> Run with given group permissions\n"
|
" -g <group> Run with given group permissions\n"
|
||||||
" -p <file> Store pid in file (process id)\n"
|
" -p <file> Store pid in file (process id)\n"
|
||||||
|
|||||||
@@ -71,6 +71,17 @@ static void probe_net_event(struct net_connection* con, int events, void *arg)
|
|||||||
probe_destroy(probe);
|
probe_destroy(probe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef LINK_SUPPORT
|
||||||
|
else if (probe->hub->config->hub_link_enabled && memcmp(probe_recvbuf, "LSUP", 4) == 0)
|
||||||
|
{
|
||||||
|
if (link_create(probe->hub, probe->connection, &probe->addr))
|
||||||
|
{
|
||||||
|
probe->connection = 0;
|
||||||
|
}
|
||||||
|
probe_destroy(probe);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* LINK_SUPPORT */
|
||||||
#ifdef SSL_SUPPORT
|
#ifdef SSL_SUPPORT
|
||||||
else if (bytes >= 11 &&
|
else if (bytes >= 11 &&
|
||||||
probe_recvbuf[0] == 22 &&
|
probe_recvbuf[0] == 22 &&
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_messag
|
|||||||
{
|
{
|
||||||
#ifdef DEBUG_SENDQ
|
#ifdef DEBUG_SENDQ
|
||||||
char* data = strndup(msg->cache, msg->length-1);
|
char* data = strndup(msg->cache, msg->length-1);
|
||||||
LOG_PROTO("send %s: \"%s\"", sid_to_string(user->id.sid), data);
|
LOG_PROTO("[user] send %s: \"%s\"", sid_to_string(user->id.sid), data);
|
||||||
free(data);
|
free(data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -132,10 +132,11 @@ struct timeout_queue* net_backend_get_timeout_queue()
|
|||||||
*/
|
*/
|
||||||
int net_backend_process()
|
int net_backend_process()
|
||||||
{
|
{
|
||||||
int res;
|
int res = 0;
|
||||||
size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
|
size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
|
||||||
|
|
||||||
res = g_backend->handler.backend_poll(g_backend->data, secs * 1000);
|
if (g_backend->common.num)
|
||||||
|
res = g_backend->handler.backend_poll(g_backend->data, secs * 1000);
|
||||||
|
|
||||||
g_backend->now = time(0);
|
g_backend->now = time(0);
|
||||||
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
|
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* 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);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -34,10 +34,41 @@ struct net_connection
|
|||||||
NET_CON_STRUCT_COMMON
|
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 int net_con_get_sd(struct net_connection* con);
|
||||||
extern void* net_con_get_ptr(struct net_connection* con);
|
extern void* net_con_get_ptr(struct net_connection* con);
|
||||||
|
|
||||||
extern struct net_connection* net_con_create();
|
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_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_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);
|
extern void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* 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)
|
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);
|
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;
|
return ipaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result* res)
|
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);
|
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;
|
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_clear(res->addr_list, &hub_free);
|
||||||
list_destroy(res->addr_list);
|
list_destroy(res->addr_list);
|
||||||
free_job(res->job);
|
free_job(res->job);
|
||||||
hub_free(res);
|
hub_free((struct net_dns_result*) res);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* 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*);
|
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result*);
|
||||||
|
|
||||||
/// When finished with the results
|
/// 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 */
|
#endif /* HAVE_UHUB_NETWORK_DNS_RESOLVER_H */
|
||||||
|
|||||||
@@ -105,6 +105,13 @@ struct ssl_context_handle* net_ssl_context_create()
|
|||||||
|
|
||||||
/* Disable SSLv2 */
|
/* Disable SSLv2 */
|
||||||
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_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);
|
SSL_CTX_set_quiet_shutdown(ctx->ssl_ctx, 1);
|
||||||
|
|
||||||
return (struct ssl_context_handle*) ctx;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -127,6 +127,10 @@
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNU__
|
||||||
|
#define POSIX_THREAD_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
#define USE_SELECT
|
#define USE_SELECT
|
||||||
#ifndef WINSOCK
|
#ifndef WINSOCK
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
enum ADC_client_state
|
enum ADC_client_state
|
||||||
{
|
{
|
||||||
ps_none, /* Not connected */
|
ps_none, /* Not connected */
|
||||||
ps_dns, /* looking up name */
|
|
||||||
ps_conn, /* Connecting... */
|
ps_conn, /* Connecting... */
|
||||||
ps_conn_ssl, /* SSL handshake */
|
ps_conn_ssl, /* SSL handshake */
|
||||||
ps_protocol, /* Have sent HSUP */
|
ps_protocol, /* Have sent HSUP */
|
||||||
@@ -68,7 +67,7 @@ struct ADC_client
|
|||||||
struct net_connection* con;
|
struct net_connection* con;
|
||||||
struct net_timer* timer;
|
struct net_timer* timer;
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
struct net_dns_job* dns_job;
|
struct net_connect_handle* connect_job;
|
||||||
struct ADC_client_address address;
|
struct ADC_client_address address;
|
||||||
char* nick;
|
char* nick;
|
||||||
char* desc;
|
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[] =
|
static const char* ADC_client_state_string[] =
|
||||||
{
|
{
|
||||||
"ps_none",
|
"ps_none",
|
||||||
"ps_dns",
|
|
||||||
"ps_conn",
|
"ps_conn",
|
||||||
"ps_conn_ssl",
|
"ps_conn_ssl",
|
||||||
"ps_protocol",
|
"ps_protocol",
|
||||||
@@ -164,18 +162,12 @@ static void event_callback(struct net_connection* con, int events, void *arg)
|
|||||||
|
|
||||||
switch (client->state)
|
switch (client->state)
|
||||||
{
|
{
|
||||||
case ps_dns:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ps_conn:
|
case ps_conn:
|
||||||
if (events == NET_EVENT_TIMEOUT)
|
if (events == NET_EVENT_TIMEOUT)
|
||||||
{
|
{
|
||||||
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
|
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events & NET_EVENT_WRITE)
|
|
||||||
ADC_client_connect_internal(client);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SSL_SUPPORT
|
#ifdef SSL_SUPPORT
|
||||||
@@ -539,11 +531,6 @@ struct ADC_client* ADC_client_create(const char* nickname, const char* descripti
|
|||||||
ADC_TRACE;
|
ADC_TRACE;
|
||||||
struct ADC_client* client = (struct ADC_client*) hub_malloc_zero(sizeof(struct ADC_client));
|
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);
|
ADC_client_set_state(client, ps_none);
|
||||||
|
|
||||||
client->nick = hub_strdup(nickname);
|
client->nick = hub_strdup(nickname);
|
||||||
@@ -570,40 +557,42 @@ void ADC_client_destroy(struct ADC_client* client)
|
|||||||
hub_free(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)
|
int ADC_client_connect(struct ADC_client* client, const char* address)
|
||||||
{
|
{
|
||||||
ADC_TRACE;
|
ADC_TRACE;
|
||||||
if (client->state == ps_none)
|
if (client->state == ps_none)
|
||||||
{
|
{
|
||||||
// Parse address and start name resolving!
|
|
||||||
if (!ADC_client_parse_address(client, address))
|
if (!ADC_client_parse_address(client, address))
|
||||||
return 0;
|
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));
|
ADC_client_set_state(client, ps_conn);
|
||||||
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
|
client->connect_job = net_con_connect(client->address.hostname, client->address.port, connect_callback, client);
|
||||||
{
|
if (!client->connect_job)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
ADC_client_on_disconnected(client);
|
ADC_client_on_disconnected(client);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -611,6 +600,7 @@ int ADC_client_connect_internal(struct ADC_client* client)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void ADC_client_on_connected(struct ADC_client* client)
|
static void ADC_client_on_connected(struct ADC_client* client)
|
||||||
{
|
{
|
||||||
ADC_TRACE;
|
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)
|
static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
|
||||||
{
|
{
|
||||||
ADC_TRACE;
|
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->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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ extern "C" {
|
|||||||
#include "core/commands.h"
|
#include "core/commands.h"
|
||||||
#include "core/inf.h"
|
#include "core/inf.h"
|
||||||
#include "core/hubevent.h"
|
#include "core/hubevent.h"
|
||||||
|
#include "core/link.h"
|
||||||
#include "core/plugincallback.h"
|
#include "core/plugincallback.h"
|
||||||
#include "core/plugininvoke.h"
|
#include "core/plugininvoke.h"
|
||||||
#include "core/pluginloader.h"
|
#include "core/pluginloader.h"
|
||||||
|
|||||||
@@ -21,7 +21,15 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|
||||||
|
#ifdef SYSTEMD
|
||||||
|
#define SD_JOURNAL_SUPPRESS_LOCATION
|
||||||
|
#include <systemd/sd-journal.h>
|
||||||
|
|
||||||
|
#else
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static int use_syslog = 0;
|
static int use_syslog = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -83,7 +91,9 @@ void hub_log_initialize(const char* file, int syslog)
|
|||||||
if (syslog)
|
if (syslog)
|
||||||
{
|
{
|
||||||
use_syslog = 1;
|
use_syslog = 1;
|
||||||
|
#ifndef SYSTEMD
|
||||||
openlog("uhub", LOG_PID, LOG_USER);
|
openlog("uhub", LOG_PID, LOG_USER);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -132,7 +142,9 @@ void hub_log_shutdown()
|
|||||||
if (use_syslog)
|
if (use_syslog)
|
||||||
{
|
{
|
||||||
use_syslog = 0;
|
use_syslog = 0;
|
||||||
|
#ifndef SYSTEMD
|
||||||
closelog();
|
closelog();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -212,7 +224,12 @@ void hub_log(int log_verbosity, const char *format, ...)
|
|||||||
case log_fatal: level = LOG_CRIT; break;
|
case log_fatal: level = LOG_CRIT; break;
|
||||||
case log_error: level = LOG_ERR; break;
|
case log_error: level = LOG_ERR; break;
|
||||||
case log_warning: level = LOG_WARNING; break;
|
case log_warning: level = LOG_WARNING; break;
|
||||||
case log_user: level = LOG_INFO | LOG_AUTH; 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_info: level = LOG_INFO; break;
|
||||||
case log_debug: level = LOG_DEBUG; break;
|
case log_debug: level = LOG_DEBUG; break;
|
||||||
|
|
||||||
@@ -224,8 +241,13 @@ void hub_log(int log_verbosity, const char *format, ...)
|
|||||||
if (level == 0)
|
if (level == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef SYSTEMD
|
||||||
|
sd_journal_print(level, "%s", logmsg);
|
||||||
|
|
||||||
|
#else
|
||||||
level |= (LOG_USER | LOG_DAEMON);
|
level |= (LOG_USER | LOG_DAEMON);
|
||||||
syslog(level, "%s", logmsg);
|
syslog(level, "%s", logmsg);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,84 +17,141 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if 0
|
#include "uhub.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include "rbtree.h"
|
#include "rbtree.h"
|
||||||
|
|
||||||
#define RED 0
|
// #define RB_TREE_CHECKS
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct rb_node* tree_search(struct rb_tree* tree, const void* key)
|
static struct rb_node* tree_search(struct rb_tree* tree, const void* key)
|
||||||
{
|
{
|
||||||
struct rb_node* node = tree->root;
|
struct rb_node* node = tree->root;
|
||||||
while (node)
|
while (node)
|
||||||
{
|
{
|
||||||
int res = tree->compare(key, node->key);
|
int res = tree->compare(node->key, key);
|
||||||
if (res < 0) node = node->left;
|
if (!res)
|
||||||
else if (res > 0) node = node->right;
|
break;
|
||||||
else return node;
|
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* node = tree->alloc(sizeof(struct rb_node));
|
||||||
struct rb_node* newnode = tree->alloc(sizeof(struct rb_node));
|
node->key = key;
|
||||||
newnode->key = key;
|
node->value = value;
|
||||||
newnode->value = value;
|
node->red = 1;
|
||||||
newnode->color = RED;
|
node->link[0] = 0;
|
||||||
|
node->link[1] = 0;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_red(struct rb_node* node)
|
||||||
|
{
|
||||||
|
return node && node->red;
|
||||||
|
}
|
||||||
|
|
||||||
while (node)
|
#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);
|
struct rb_node *ln = node->link[0];
|
||||||
if (res < 0) node = node->left;
|
struct rb_node *rn = node->link[1];
|
||||||
else if (res > 0) node = node->right;
|
|
||||||
else
|
/* 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 */
|
puts("Binary tree violation");
|
||||||
return node;
|
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;
|
||||||
return newnode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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));
|
struct rb_tree* tree = a(sizeof(struct rb_tree));
|
||||||
tree->compare = compare;
|
tree->compare = compare;
|
||||||
tree->alloc = a;
|
tree->alloc = a ? a : hub_malloc;
|
||||||
tree->free = f;
|
tree->free = f ? f : hub_free;
|
||||||
|
tree->root = NULL;
|
||||||
|
tree->elements = 0;
|
||||||
|
tree->iterator.node = NULL;
|
||||||
|
tree->iterator.stack = list_create();
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rb_tree_destroy(struct rb_tree* tree)
|
void rb_tree_destroy(struct rb_tree* tree)
|
||||||
{
|
{
|
||||||
rb_tree_free f = tree->free;
|
list_destroy(tree->iterator.stack);
|
||||||
f(tree);
|
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);
|
struct rb_node* node;
|
||||||
if (node)
|
if (tree_search(tree, key))
|
||||||
return (void*) node->value;
|
return 0;
|
||||||
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)
|
void* rb_tree_get(struct rb_tree* tree, const void* key)
|
||||||
{
|
{
|
||||||
struct rb_node* node = tree_search(tree, key);
|
struct rb_node* node = tree_search(tree, key);
|
||||||
if (node)
|
if (node)
|
||||||
return node->value;
|
return (void*) node->value;
|
||||||
return 0;
|
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
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,19 +20,122 @@
|
|||||||
#ifndef HAVE_UHUB_RED_BLACK_TREE_H
|
#ifndef HAVE_UHUB_RED_BLACK_TREE_H
|
||||||
#define 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 int (*rb_tree_compare)(const void* a, const void* b);
|
||||||
typedef void* (*rb_tree_alloc)(size_t);
|
typedef void* (*rb_tree_alloc)(size_t);
|
||||||
typedef void (*rb_tree_free)(void*);
|
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_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);
|
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 */
|
#endif /* HAVE_UHUB_RED_BLACK_TREE_H */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user