Compare commits

..

56 Commits

Author SHA1 Message Date
Jan Vidar Krey
51fba8a7a1 Added support for connecting the hub to an upstream master hub (slave mode). 2013-02-07 12:17:26 +01:00
Jan Vidar Krey
a7898779cb Started working on hub linking support (currently disabled). 2013-02-05 22:45:20 +01:00
Jan Vidar Krey
f6f7c7a3a4 Make sure we compile release builds with NDEBUG defined (to disable asserts). 2013-02-05 22:44:31 +01:00
Jan Vidar Krey
1fbde2b0fd Re-factored the ADC client code to use the new connection establishment API. 2013-02-05 22:43:59 +01:00
Jan Vidar Krey
92b65a0e14 Created a connection establishment API.
This API provides transparent asynchronous DNS lookups
with both IPv4 and IPv6 support, and in addition will try
to connect to all addresses until one of them work.

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

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

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

Added a copy of exotic in the repository

exotic automatically generates the skeleton code around the autotests in order to schedule
the tests.
2012-10-25 17:27:45 +02:00
Jan Vidar Krey
d4763e54db Fixed memory leaks. 2012-10-25 04:13:45 +02:00
Jan Vidar Krey
38b19f633d Fix memory leaks and report "host is not found" correctly. 2012-10-25 04:13:05 +02:00
Jan Vidar Krey
d106ecdc65 Bugfixes for pthreads. 2012-10-25 04:10:42 +02:00
Jan Vidar Krey
99a2307d1d Simple compile fix. 2012-10-25 00:44:21 +02:00
Jan Vidar Krey
470c936e63 Converted the DNS resolver to work with the new threading API abstraction. 2012-10-25 00:40:16 +02:00
Jan Vidar Krey
168fc5bfcc Abstracted the threading code so that it works with Winthreads and pthreads. 2012-10-25 00:39:44 +02:00
Jan Vidar Krey
b34b90f95a Start using the async DNS API. 2012-10-24 23:22:10 +02:00
Jan Vidar Krey
793790d089 Initial implementation of an async DNS client API with getaddrinfo + pthreads. 2012-10-24 23:19:14 +02:00
Jan Vidar Krey
19559f4974 Make sure we count OpenSSL traffic for the byte IO statistics. 2012-10-18 11:40:18 +02:00
Jan Vidar Krey
b999068555 Use OpenSSL by default. 2012-10-17 19:02:32 +00:00
Jan Vidar Krey
4385266bb7 Free all memory in case the hub does not start because of port already in use. 2012-10-17 20:54:46 +02:00
Jan Vidar Krey
c50eb90bee Removed the last bits of OpenSSL code called directly 2012-10-17 20:53:05 +02:00
Jan Vidar Krey
1e0927f510 Update copyright year. 2012-10-17 20:00:52 +02:00
Jan Vidar Krey
b9d43c784c Merge branch 'master' of github.com:janvidar/uhub
Conflicts:
	CMakeLists.txt
2012-10-17 19:59:02 +02:00
Jan Vidar Krey
46d365cafe Merge branch 'gnutls_work' 2012-10-17 15:47:16 +02:00
Jan Vidar Krey
3a8c91004e fixup! Add possibility to specify UHUB_REVISION manually. 2012-10-15 20:27:43 +02:00
Boris Pek
deaadd053b Add possibility to specify UHUB_REVISION manually. 2012-10-15 20:24:42 +02:00
Jan Vidar Krey
c28a5d3a9b Merge branch 'master' of github.com:janvidar/uhub 2012-10-15 20:20:17 +02:00
Jan Vidar Krey
8b06a75d8e Revert "Add possibility to specify UHUB_REVISION manually."
This reverts commit dcfcf3110d.
2012-10-15 00:24:59 +02:00
Jan Vidar Krey
e6cb7a7e10 Revert "Add possibility to specify UHUB_REVISION manually."
This reverts commit dcfcf3110d.
2012-10-14 22:24:33 +00:00
Jan Vidar Krey
82caa6b81f Merge pull request #14 from tehnick/fix-build-on-kfreebsd-any
Fix build in Debian GNU/kFreeBSD.
2012-10-14 15:19:21 -07:00
Boris Pek
ddfbb919a7 Fix build in Debian GNU/kFreeBSD. 2012-10-14 02:13:10 +03:00
Jan Vidar Krey
7fae42aa4d Merge pull request #12 from tehnick/fix-version
Add possibility to specify UHUB_REVISION manually.
2012-10-13 10:34:39 -07:00
Jan Vidar Krey
ba59e1a00e Merge pull request #13 from tehnick/cmake-up
Simplify CMakeLists.txt
2012-10-13 10:34:23 -07:00
Jan Vidar Krey
4fcfee8e82 Merge pull request #11 from tehnick/fix-plugins-location
Use directory /usr/lib/uhub/ instead of /var/lib/uhub/
2012-10-13 10:33:09 -07:00
Boris Pek
63171b0ce2 Simplify CMakeLists.txt 2012-10-13 20:13:15 +03:00
Boris Pek
dcfcf3110d Add possibility to specify UHUB_REVISION manually. 2012-10-13 19:46:44 +03:00
Boris Pek
53a5f5a243 Use directory /usr/lib/uhub/ instead of /var/lib/uhub/
in according with FHS (Filesystem Hierarchy Standard).
2012-10-13 18:48:24 +03:00
Jan Vidar Krey
af083efb0c fixup! Don't compile the utils files multiple times. 2012-10-09 22:14:38 +02:00
Jan Vidar Krey
e7aa63f3bd Don't compile the utils files multiple times. 2012-10-09 22:09:25 +02:00
Jan Vidar Krey
279c932b67 fixup! Add install make rule. 2012-10-09 19:31:54 +02:00
52 changed files with 4602 additions and 364 deletions

2
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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" OFF) 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,63 +36,32 @@ 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})
set (network_SOURCES file (GLOB uhub_SOURCES ${PROJECT_SOURCE_DIR}/core/*.c)
${PROJECT_SOURCE_DIR}/network/backend.c list (REMOVE_ITEM uhub_SOURCES
${PROJECT_SOURCE_DIR}/network/connection.c ${PROJECT_SOURCE_DIR}/core/gen_config.c
${PROJECT_SOURCE_DIR}/network/epoll.c ${PROJECT_SOURCE_DIR}/core/main.c
${PROJECT_SOURCE_DIR}/network/kqueue.c
${PROJECT_SOURCE_DIR}/network/select.c
${PROJECT_SOURCE_DIR}/network/timeout.c
${PROJECT_SOURCE_DIR}/network/timer.c
${PROJECT_SOURCE_DIR}/network/network.c
${PROJECT_SOURCE_DIR}/network/openssl.c
${PROJECT_SOURCE_DIR}/network/ipcalc.c
) )
set (uhub_SOURCES file (GLOB adc_SOURCES ${PROJECT_SOURCE_DIR}/adc/*.c)
${PROJECT_SOURCE_DIR}/core/auth.c file (GLOB network_SOURCES ${PROJECT_SOURCE_DIR}/network/*.c)
${PROJECT_SOURCE_DIR}/core/command_parser.c file (GLOB utils_SOURCES ${PROJECT_SOURCE_DIR}/util/*.c)
${PROJECT_SOURCE_DIR}/core/commands.c
${PROJECT_SOURCE_DIR}/core/config.c
${PROJECT_SOURCE_DIR}/core/eventqueue.c
${PROJECT_SOURCE_DIR}/core/hub.c
${PROJECT_SOURCE_DIR}/core/hubevent.c
${PROJECT_SOURCE_DIR}/core/inf.c
${PROJECT_SOURCE_DIR}/core/ioqueue.c
${PROJECT_SOURCE_DIR}/core/netevent.c
${PROJECT_SOURCE_DIR}/core/probe.c
${PROJECT_SOURCE_DIR}/core/route.c
${PROJECT_SOURCE_DIR}/core/user.c
${PROJECT_SOURCE_DIR}/core/usermanager.c
${PROJECT_SOURCE_DIR}/core/plugincallback.c
${PROJECT_SOURCE_DIR}/core/plugininvoke.c
${PROJECT_SOURCE_DIR}/core/pluginloader.c
)
set (adc_SOURCES
${PROJECT_SOURCE_DIR}/adc/message.c
${PROJECT_SOURCE_DIR}/adc/sid.c
)
set (utils_SOURCES
${PROJECT_SOURCE_DIR}/util/cbuffer.c
${PROJECT_SOURCE_DIR}/util/config_token.c
${PROJECT_SOURCE_DIR}/util/credentials.c
${PROJECT_SOURCE_DIR}/util/floodctl.c
${PROJECT_SOURCE_DIR}/util/getopt.c
${PROJECT_SOURCE_DIR}/util/list.c
${PROJECT_SOURCE_DIR}/util/log.c
${PROJECT_SOURCE_DIR}/util/memory.c
${PROJECT_SOURCE_DIR}/util/misc.c
${PROJECT_SOURCE_DIR}/util/rbtree.c
${PROJECT_SOURCE_DIR}/util/tiger.c
)
set (adcclient_SOURCES set (adcclient_SOURCES
${PROJECT_SOURCE_DIR}/tools/adcclient.c ${PROJECT_SOURCE_DIR}/tools/adcclient.c
@@ -100,36 +71,31 @@ set (adcclient_SOURCES
add_library(adc STATIC ${adc_SOURCES}) add_library(adc STATIC ${adc_SOURCES})
add_library(network STATIC ${network_SOURCES}) add_library(network STATIC ${network_SOURCES})
add_library(utils STATIC ${utils_SOURCES}) add_library(utils STATIC ${utils_SOURCES})
if(CMAKE_COMPILER_IS_GNUCC)
set_target_properties(utils PROPERTIES COMPILE_FLAGS -fPIC)
set_target_properties(network PROPERTIES COMPILE_FLAGS -fPIC)
endif()
add_dependencies(adc utils) 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 ${utils_SOURCES}) add_library(mod_example MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_example.c)
add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c ${utils_SOURCES} ${network_SOURCES}) add_library(mod_welcome MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_welcome.c)
add_library(mod_logging MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_logging.c ${utils_SOURCES} ${PROJECT_SOURCE_DIR}/adc/sid.c ${network_SOURCES}) add_library(mod_logging MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_logging.c ${PROJECT_SOURCE_DIR}/adc/sid.c)
add_library(mod_auth_simple MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_simple.c ${utils_SOURCES}) add_library(mod_auth_simple MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_simple.c )
add_library(mod_chat_history MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_chat_history.c ${utils_SOURCES}) 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 ${utils_SOURCES}) 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 ${utils_SOURCES}) 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 ${utils_SOURCES})
add_executable(uhub-passwd ${PROJECT_SOURCE_DIR}/tools/uhub-passwd.c ${PROJECT_SOURCE_DIR}/util/misc.c ${PROJECT_SOURCE_DIR}/util/memory.c ${PROJECT_SOURCE_DIR}/util/log.c ${PROJECT_SOURCE_DIR}/util/list.c)
target_link_libraries(mod_auth_sqlite sqlite3)
target_link_libraries(uhub-passwd sqlite3)
set_target_properties(mod_auth_sqlite PROPERTIES PREFIX "")
if (UNIX)
target_link_libraries(uhub pthread)
endif()
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()
@@ -139,30 +105,59 @@ 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_welcome utils)
target_link_libraries(mod_auth_simple utils)
target_link_libraries(mod_auth_sqlite ${SQLITE3_LIBRARIES} utils)
target_link_libraries(mod_chat_history utils)
target_link_libraries(mod_no_guest_downloads utils)
target_link_libraries(mod_chat_only utils)
target_link_libraries(mod_logging utils)
target_link_libraries(mod_topic utils)
target_link_libraries(utils network)
target_link_libraries(mod_welcome 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) target_link_libraries(uhub-admin adcclient adc network utils 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})
target_link_libraries(adcrush adcclient adc network utils) target_link_libraries(adcrush adcclient adc network utils pthread)
endif() endif()
endif() endif()
if(GIT_FOUND AND IS_DIRECTORY ".git") if (NOT UHUB_REVISION AND GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} show -s --pretty=format:%h OUTPUT_VARIABLE UHUB_REVISION) execute_process(COMMAND ${GIT_EXECUTABLE} show -s --pretty=format:%h
set (UHUB_GIT_VERSION "${UHUB_VERSION_MAJOR}.${UHUB_VERSION_MINOR}.${UHUB_VERSION_PATCH}-git-${UHUB_REVISION}") WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
else() OUTPUT_VARIABLE UHUB_REVISION_TEMP
set (UHUB_GIT_VERSION "${UHUB_VERSION_MAJOR}.${UHUB_VERSION_MINOR}.${UHUB_VERSION_PATCH}-release") OUTPUT_STRIP_TRAILING_WHITESPACE)
if (UHUB_REVISION_TEMP)
set (UHUB_REVISION "git-${UHUB_REVISION_TEMP}")
endif() endif()
endif()
if (NOT UHUB_REVISION)
set (UHUB_REVISION "release")
endif()
set (UHUB_GIT_VERSION "${UHUB_VERSION_MAJOR}.${UHUB_VERSION_MINOR}.${UHUB_VERSION_PATCH}-${UHUB_REVISION}")
message (STATUS "Configuring uhub version: ${UHUB_GIT_VERSION}")
if(OPENSSL_FOUND) if(OPENSSL_FOUND)
set(SSL_LIBS ${OPENSSL_LIBRARIES}) set(SSL_LIBS ${OPENSSL_LIBRARIES})
@@ -178,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()
@@ -188,27 +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 /var/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}/uhub.conf ${CMAKE_SOURCE_DIR}/plugins.conf ${CMAKE_SOURCE_DIR}/rules.txt ${CMAKE_SOURCE_DIR}/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()

View File

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

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

1032
autotest/test.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@ extern int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, st
static void inf_create_hub() 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) \
do { \
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \ struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \ int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
adc_msg_free(msg); \ adc_msg_free(msg); \
if (ok == EXPECT) \ if (ok == EXPECT) \
user_set_info(inf_user, 0); \ user_set_info(inf_user, 0); \
return ok == EXPECT; return ok == EXPECT; \
} while(0)
EXO_TEST(inf_ok_1, { CHECK_INF("BINF AAAB NIFriend IDGNSSMURMD7K466NGZIHU65TP3S3UZSQ6MN5B2RI PD3A4545WFVGZLSGUXZLG7OS6ULQUVG3HM2T63I7Y\n", 0); }); 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);

View File

@@ -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;
}); });

View File

@@ -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;
}); });

View File

@@ -97,15 +97,25 @@ EXO_TEST(base32_invalid_31, { return !is_valid_base32_char('@'); });
EXO_TEST(utf8_valid_1, { return is_valid_utf8("abcdefghijklmnopqrstuvwxyz"); }); EXO_TEST(utf8_valid_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
View File

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

View File

@@ -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
View File

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

View File

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

View File

@@ -11,7 +11,7 @@
# Parameters: # Parameters:
# file: path/filename for database. # file: path/filename for database.
# #
plugin /var/lib/uhub/mod_auth_sqlite.so "file=/etc/uhub/users.db" plugin /usr/lib/uhub/mod_auth_sqlite.so "file=/etc/uhub/users.db"
# Log file writer # Log file writer
@@ -19,10 +19,10 @@ plugin /var/lib/uhub/mod_auth_sqlite.so "file=/etc/uhub/users.db"
# Parameters: # Parameters:
# file: path/filename for log file. # file: path/filename for log file.
# syslog: if true then syslog is used instead of writing to a file (Unix only) # syslog: if true then syslog is used instead of writing to a file (Unix only)
plugin /var/lib/uhub/mod_logging.so "file=/var/log/uhub.log" plugin /usr/lib/uhub/mod_logging.so "file=/var/log/uhub.log"
# A simple example plugin # A simple example plugin
# plugin /var/lib/uhub/mod_example.so # plugin /usr/lib/uhub/mod_example.so
# A plugin sending a welcome message. # A plugin sending a welcome message.
# #
# This plugin provides the following commands: # This plugin provides the following commands:
@@ -46,7 +46,7 @@ plugin /var/lib/uhub/mod_logging.so "file=/var/log/uhub.log"
# %p - 'am' or 'pm' # %p - 'am' or 'pm'
# %M - Minutes (00-59) (Hub local time) # %M - Minutes (00-59) (Hub local time)
# %S - Seconds (00-60) (Hub local time) # %S - Seconds (00-60) (Hub local time)
plugin /var/lib/uhub/mod_welcome.so "motd=/etc/uhub/motd.txt rules=/etc/uhub/rules.txt" plugin /usr/lib/uhub/mod_welcome.so "motd=/etc/uhub/motd.txt rules=/etc/uhub/rules.txt"
# Load the chat history plugin. # Load the chat history plugin.
# #
@@ -58,5 +58,5 @@ plugin /var/lib/uhub/mod_welcome.so "motd=/etc/uhub/motd.txt rules=/etc/uhub/rul
# history_max: the maximum number of messages to keep in history # history_max: the maximum number of messages to keep in history
# history_default: when !history is provided without arguments, then this default number of messages are returned. # history_default: when !history is provided without arguments, then this default number of messages are returned.
# history_connect: the number of chat history messages to send when users connect (0 = do not send any history) # history_connect: the number of chat history messages to send when users connect (0 = do not send any history)
plugin /var/lib/uhub/mod_chat_history.so "history_max=200 history_default=10 history_connect=5" plugin /usr/lib/uhub/mod_chat_history.so "history_max=200 history_default=10 history_connect=5"

View File

@@ -41,7 +41,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/init.d
mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
mkdir -p $RPM_BUILD_ROOT/etc/sysconfig mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1 mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1
mkdir -p $RPM_BUILD_ROOT/var/lib/uhub mkdir -p $RPM_BUILD_ROOT/usr/lib/uhub
install uhub $RPM_BUILD_ROOT/usr/bin/ install uhub $RPM_BUILD_ROOT/usr/bin/
install uhub-passwd $RPM_BUILD_ROOT/usr/bin/ install uhub-passwd $RPM_BUILD_ROOT/usr/bin/
@@ -52,7 +52,7 @@ install -m644 doc/init.d.RedHat/etc/sysconfig/uhub $RPM_BUILD_ROOT/etc/sysconfi
install -m644 doc/init.d.RedHat/etc/logrotate.d/uhub $RPM_BUILD_ROOT/etc/logrotate.d/ install -m644 doc/init.d.RedHat/etc/logrotate.d/uhub $RPM_BUILD_ROOT/etc/logrotate.d/
/bin/gzip -9c doc/uhub.1 > doc/uhub.1.gz && /bin/gzip -9c doc/uhub.1 > doc/uhub.1.gz &&
install -m644 doc/uhub.1.gz $RPM_BUILD_ROOT/usr/share/man/man1 install -m644 doc/uhub.1.gz $RPM_BUILD_ROOT/usr/share/man/man1
install -m644 mod_*.so $RPM_BUILD_ROOT/var/lib/uhub install -m644 mod_*.so $RPM_BUILD_ROOT/usr/lib/uhub
%files %files

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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) */

View File

@@ -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);
} }

View File

@@ -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 */

View File

@@ -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));

View File

@@ -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
View 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
View 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 */

View File

@@ -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;
@@ -136,10 +144,25 @@ int main_loop()
{ {
hub = hub_start_service(&configuration); hub = hub_start_service(&configuration);
if (!hub) if (!hub)
{
acl_shutdown(&acl);
free_config(&configuration);
net_destroy();
hub_log_shutdown();
return -1; return -1;
}
#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);
@@ -210,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"

View File

@@ -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 &&

View File

@@ -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

View File

@@ -132,9 +132,10 @@ 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);
if (g_backend->common.num)
res = g_backend->handler.backend_poll(g_backend->data, secs * 1000); res = g_backend->handler.backend_poll(g_backend->data, secs * 1000);
g_backend->now = time(0); g_backend->now = time(0);
@@ -146,6 +147,9 @@ int net_backend_process()
return 0; return 0;
} }
// Process pending DNS results
net_dns_process();
g_backend->handler.backend_process(g_backend->data, res); g_backend->handler.backend_process(g_backend->data, res);
net_cleanup_process(g_backend->cleaner); net_cleanup_process(g_backend->cleaner);

View File

@@ -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
@@ -20,11 +20,6 @@
#include "uhub.h" #include "uhub.h"
#include "network/common.h" #include "network/common.h"
#ifdef SSL_SUPPORT
void net_stats_add_tx(size_t bytes);
void net_stats_add_rx(size_t bytes);
#endif
static int is_blocked_or_interrupted() static int is_blocked_or_interrupted()
{ {
int err = net_error(); int err = net_error();
@@ -150,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);
}

View File

@@ -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);

389
src/network/dnsresolver.c Normal file
View File

@@ -0,0 +1,389 @@
/*
* 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"
static struct net_dns_job* find_and_remove_job(struct net_dns_job* job);
static struct net_dns_result* find_and_remove_result(struct net_dns_job* job);
struct net_dns_job
{
net_dns_job_cb callback;
void* ptr;
char* host;
int af;
#ifdef DEBUG_LOOKUP_TIME
struct timeval time_start;
struct timeval time_finish;
#endif
uhub_thread_t* thread_handle;
};
struct net_dns_result
{
struct linked_list* addr_list;
struct net_dns_job* job;
};
static void free_job(struct net_dns_job* job)
{
if (job)
{
hub_free(job->host);
hub_free(job);
}
}
static void shutdown_free_jobs(void* ptr)
{
struct net_dns_job* job = (struct net_dns_job*) ptr;
uhub_thread_cancel(job->thread_handle);
uhub_thread_join(job->thread_handle);
free_job(job);
}
static void shutdown_free_results(void* ptr)
{
struct net_dns_result* result = (struct net_dns_result*) ptr;
uhub_thread_join(result->job->thread_handle);
net_dns_result_free(result);
}
// NOTE: Any job manipulating the members of this
// struct must lock the mutex!
struct net_dns_subsystem
{
struct linked_list* jobs; // currently running jobs
struct linked_list* results; // queue of results that are awaiting being delivered to callback.
uhub_mutex_t mutex;
};
static struct net_dns_subsystem* g_dns = NULL;
void net_dns_initialize()
{
LOG_TRACE("net_dns_initialize()");
g_dns = (struct net_dns_subsystem*) hub_malloc_zero(sizeof(struct net_dns_subsystem));
g_dns->jobs = list_create();
g_dns->results = list_create();
uhub_mutex_init(&g_dns->mutex);
}
void net_dns_destroy()
{
struct net_dns_job* job;
struct net_dns_result* result;
uhub_mutex_lock(&g_dns->mutex);
LOG_TRACE("net_dns_destroy(): jobs=%d", (int) list_size(g_dns->jobs));
list_clear(g_dns->jobs, &shutdown_free_jobs);
LOG_TRACE("net_dns_destroy(): results=%d", (int) list_size(g_dns->results));
list_clear(g_dns->results, &shutdown_free_results);
uhub_mutex_unlock(&g_dns->mutex);
list_destroy(g_dns->jobs);
list_destroy(g_dns->results);
uhub_mutex_destroy(&g_dns->mutex);
hub_free(g_dns);
g_dns = NULL;
}
static void dummy_free(void* ptr)
{
}
void net_dns_process()
{
struct net_dns_result* result;
uhub_mutex_lock(&g_dns->mutex);
LOG_DUMP("net_dns_process(): jobs=%d, results=%d", (int) list_size(g_dns->jobs), (int) list_size(g_dns->results));
for (result = (struct net_dns_result*) list_get_first(g_dns->results); result; result = (struct net_dns_result*) list_get_next(g_dns->results))
{
struct net_dns_job* job = result->job;
#ifdef DEBUG_LOOKUP_TIME
struct timeval time_result;
timersub(&result->job->time_finish, &result->job->time_start, &time_result);
LOG_TRACE("DNS lookup took %d ms", (time_result.tv_sec * 1000) + (time_result.tv_usec / 1000));
#endif
// wait for the work thread to finish
uhub_thread_join(job->thread_handle);
// callback - should we delete the data immediately?
if (job->callback(job, result))
{
net_dns_result_free(result);
}
else
{
/* Caller wants to keep the result data, and
* thus needs to call net_dns_result_free() to release it later.
* We only clean up the job data here and keep the results intact.
*/
result->job = NULL;
free_job(job);
}
}
list_clear(g_dns->results, &dummy_free);
uhub_mutex_unlock(&g_dns->mutex);
}
static void* job_thread_resolve_name(void* ptr)
{
struct net_dns_job* job = (struct net_dns_job*) ptr;
struct addrinfo hints, *result, *it;
struct net_dns_result* dns_results;
int ret;
memset(&hints, 0, sizeof(hints));
hints.ai_family = job->af;
hints.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo(job->host, NULL, &hints, &result);
if (ret != 0 && ret != EAI_NONAME)
{
LOG_TRACE("getaddrinfo() failed: %s", gai_strerror(ret));
return NULL;
}
dns_results = (struct net_dns_result*) hub_malloc(sizeof(struct net_dns_result));
dns_results->addr_list = list_create();
dns_results->job = job;
if (ret != EAI_NONAME)
{
for (it = result; it; it = it->ai_next)
{
struct ip_addr_encap* ipaddr = hub_malloc_zero(sizeof(struct ip_addr_encap));
ipaddr->af = it->ai_family;
if (it->ai_family == AF_INET)
{
struct sockaddr_in* addr4 = (struct sockaddr_in*) it->ai_addr;
memcpy(&ipaddr->internal_ip_data.in, &addr4->sin_addr, sizeof(struct in_addr));
}
else if (it->ai_family == AF_INET6)
{
struct sockaddr_in6* addr6 = (struct sockaddr_in6*) it->ai_addr;
memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
}
else
{
LOG_TRACE("getaddrinfo() returned result with unknown address family: %d", it->ai_family);
hub_free(ipaddr);
continue;
}
LOG_DUMP("getaddrinfo() - Address (%d) %s for \"%s\"", ret++, ip_convert_to_string(ipaddr), job->host);
list_append(dns_results->addr_list, ipaddr);
}
freeaddrinfo(result);
}
else
{
/* hm */
}
#ifdef DEBUG_LOOKUP_TIME
gettimeofday(&job->time_finish, NULL);
#endif
uhub_mutex_lock(&g_dns->mutex);
list_remove(g_dns->jobs, job);
list_append(g_dns->results, dns_results);
uhub_mutex_unlock(&g_dns->mutex);
return dns_results;
}
extern struct net_dns_job* net_dns_gethostbyname(const char* host, int af, net_dns_job_cb callback, void* ptr)
{
struct net_dns_job* job = (struct net_dns_job*) hub_malloc_zero(sizeof(struct net_dns_job));
job->host = strdup(host);
job->af = af;
job->callback = callback;
job->ptr = ptr;
#ifdef DEBUG_LOOKUP_TIME
gettimeofday(&job->time_start, NULL);
#endif
// FIXME - scheduling - what about a max number of threads?
uhub_mutex_lock(&g_dns->mutex);
job->thread_handle = uhub_thread_create(job_thread_resolve_name, job);
if (!job->thread_handle)
{
LOG_WARN("Unable to create thread");
free_job(job);
job = NULL;
}
else
{
list_append(g_dns->jobs, job);
}
uhub_mutex_unlock(&g_dns->mutex);
return job;
}
extern struct net_dns_job* net_dns_gethostbyaddr(struct ip_addr_encap* ipaddr, net_dns_job_cb callback, void* ptr)
{
struct net_dns_job* job = (struct net_dns_job*) hub_malloc_zero(sizeof(struct net_dns_job));
// job->host = strdup(addr);
job->af = ipaddr->af;
job->callback = callback;
job->ptr = ptr;
// if (pthread_create(&job->thread_handle, NULL, start_job, job))
// {
// free_job(job);
// return NULL;
// }
return job;
}
// NOTE: mutex must be locked first!
static struct net_dns_job* find_and_remove_job(struct net_dns_job* job)
{
struct net_dns_job* it;
for (it = (struct net_dns_job*) list_get_first(g_dns->jobs); it; it = (struct net_dns_job*) list_get_next(g_dns->jobs))
{
if (it == job)
{
list_remove(g_dns->jobs, it);
return job;
}
}
return NULL;
}
// NOTE: mutex must be locked first!
static struct net_dns_result* find_and_remove_result(struct net_dns_job* job)
{
struct net_dns_result* it;
for (it = (struct net_dns_result*) list_get_first(g_dns->results); it; it = (struct net_dns_result*) list_get_next(g_dns->results))
{
if (it->job == job)
{
list_remove(g_dns->results, it);
return it;
}
}
return NULL;
}
extern int net_dns_job_cancel(struct net_dns_job* job)
{
int retval = 0;
struct net_dns_result* res;
LOG_TRACE("net_dns_job_cancel(): job=%p, name=%s", job, job->host);
/*
* This function looks up the job in the jobs queue (which contains only active jobs)
* If that is found then the thread is cancelled, and the object is deleted.
* If the job was not found, that is either because it was an invalid job, or because
* it was already finished. At which point it was not deleted.
* If the job is already finished, but the result has not been delivered, then this
* deletes the result and the job.
*/
uhub_mutex_lock(&g_dns->mutex);
if (find_and_remove_job(job))
{
// job still active - cancel it, then close it.
uhub_thread_cancel(job->thread_handle);
uhub_thread_join(job->thread_handle);
free_job(job);
retval = 1;
}
else if ((res = find_and_remove_result(job)))
{
// job already finished - close it.
uhub_thread_join(job->thread_handle);
net_dns_result_free(res);
}
uhub_mutex_unlock(&g_dns->mutex);
return retval;
}
extern struct net_dns_result* net_dns_job_sync_wait(struct net_dns_job* job)
{
struct net_dns_result* res = NULL;
// Wait for job to finish (if not already)
// This should make sure the job is removed from jobs and a result is
// present in results.
uhub_thread_join(job->thread_handle);
// Remove the result in order to prevent the callback from being called.
uhub_mutex_lock(&g_dns->mutex);
res = find_and_remove_result(job);
uhub_assert(res != NULL);
res->job = NULL;
free_job(job);
uhub_mutex_unlock(&g_dns->mutex);
return res;
}
void* net_dns_job_get_ptr(const struct net_dns_job* job)
{
return job->ptr;
}
extern size_t net_dns_result_size(const struct net_dns_result* res)
{
return list_size(res->addr_list);
}
extern struct ip_addr_encap* net_dns_result_first(const struct net_dns_result* res)
{
struct ip_addr_encap* ipaddr = list_get_first(res->addr_list);
LOG_TRACE("net_dns_result_first() - Address: %s", ipaddr ? ip_convert_to_string(ipaddr) : "(no address)");
return ipaddr;
}
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result* res)
{
struct ip_addr_encap* ipaddr = list_get_next(res->addr_list);
LOG_TRACE("net_dns_result_next() - Address: %s", ipaddr ? ip_convert_to_string(ipaddr) : "(no more addresses)");
return ipaddr;
}
extern void net_dns_result_free(const struct net_dns_result* res)
{
if (!res)
return;
list_clear(res->addr_list, &hub_free);
list_destroy(res->addr_list);
free_job(res->job);
hub_free((struct net_dns_result*) res);
}

119
src/network/dnsresolver.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* 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_NETWORK_DNS_RESOLVER_H
#define HAVE_UHUB_NETWORK_DNS_RESOLVER_H
struct net_dns_job;
struct net_dns_result;
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
/// Initialize the DNS subsystem
void net_dns_initialize();
/// Shutdown and destroy the DNS subsystem. This will cancel any pending DNS jobs.
void net_dns_destroy();
/// Process finished DNS lookups.
void net_dns_process();
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
/**
* Callback to be called when the DNS job has finished.
* If the name or address could not be resolved to an IP address (host not found, or found but has no address)
* then 'result' contains an empty list (@see net_dns_result_size()).
* If resolving caused an error then result is NULL.
*
* After this callback is called the job is considered done, and is freed.
*
* @param If 1 is returned then result is deleted immediately after the callback,
* otherwise the callback becomes owner of the result data which must be freed with net_dns_result_free().
*/
typedef int (*net_dns_job_cb)(struct net_dns_job*, const struct net_dns_result* result);
/**
* Resolve a hostname.
*
* @param host the hostname to be resolved.
* @param af the indicated address family. Should be AF_INET, AF_INET6 (or AF_UNSPEC - which means both AF_INET and AF_INET6.
* @param callback the callback to be called when the hostname has been resolved.
* @param ptr A user-defined pointer value.
*
* @return A resolve job handle if the job has successfully started or NULL if unable to start resolving.
*/
extern struct net_dns_job* net_dns_gethostbyname(const char* host, int af, net_dns_job_cb callback, void* ptr);
/**
* Perform a reverse DNS lookup for a given IP address.
*
* @see net_dns_gethostbyname()
* @return A resolve job handle if the job has successfully started or NULL if unable to start resolving.
*/
extern struct net_dns_job* net_dns_gethostbyaddr(struct ip_addr_encap* ipaddr, net_dns_job_cb callback, void* ptr);
/**
* Cancel a DNS lookup job.
*
* It is only allowed to call this once after a job has been started (@see net_dns_gethostbyname(), @see net_dns_gethostbyaddr())
* but before it has finished and delivered a to the callback address (@see net_dns_job_cb).
*
* @returns 1 if cancelled, or 0 if not cancelled (because the job was not found!)
*/
extern int net_dns_job_cancel(struct net_dns_job* job);
/**
* Wait in a synchronous manner for a running DNS job to finished and
* return the result here.
* The job must be started with net_dns_gethostbyaddr/net_dns_gethostbyname
* and not finished or cancelled.
*
* If this function is invoked then the callback function will not be called and
* can therefore be NULL.
*
* <code>
* struct net_dns_job* job = net_dns_gethostbyname("www.example.com", AF_INET, NULL, NULL);
* struct net_dns_result* net_dns_job_sync_wait(job);
* </code>
*/
extern struct net_dns_result* net_dns_job_sync_wait(struct net_dns_job* job);
/**
* Returns the user specified pointer assigned to the resolving job
*/
extern void* net_dns_job_get_ptr(const struct net_dns_job* job);
/// Returns the number of results provided. This is 0 if the host could not be found (or has no matching IP address).
extern size_t net_dns_result_size(const struct net_dns_result*);
/// Returns the first result (if net_dns_result_size > 0), or NULL if not first result exists.
extern struct ip_addr_encap* net_dns_result_first(const struct net_dns_result*);
/// Returns the next result or NULL if no next result exists.
extern struct ip_addr_encap* net_dns_result_next(const struct net_dns_result*);
/// When finished with the results
extern void net_dns_result_free(const struct net_dns_result*);
#endif /* HAVE_UHUB_NETWORK_DNS_RESOLVER_H */

View File

@@ -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-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
@@ -49,23 +49,21 @@ int net_initialize()
} }
#endif /* WINSOCK */ #endif /* WINSOCK */
if (!net_backend_init()) if (!net_backend_init()
#ifdef SSL_SUPPORT
|| !net_ssl_library_init()
#endif
)
{ {
#ifdef WINSOCK #ifdef WINSOCK
WSACleanup(); WSACleanup();
#endif #endif
return -1; return -1;
} }
net_dns_initialize();
net_stats_initialize(); net_stats_initialize();
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
LOG_TRACE("Initializing OpenSSL...");
SSL_library_init();
SSL_load_error_strings();
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */
net_initialized = 1; net_initialized = 1;
return 0; return 0;
} }
@@ -99,14 +97,12 @@ int net_destroy()
{ {
LOG_TRACE("Shutting down network monitor"); LOG_TRACE("Shutting down network monitor");
net_dns_destroy();
net_backend_shutdown(); net_backend_shutdown();
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL net_ssl_library_shutdown();
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
#ifdef WINSOCK #ifdef WINSOCK
@@ -499,7 +495,6 @@ int net_socket_create(int af, int type, int protocol)
} }
} }
#endif #endif
return sd; return sd;
} }

View File

@@ -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-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

View File

@@ -24,15 +24,17 @@
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL #ifdef SSL_USE_OPENSSL
#define NETWORK_DUMP_DEBUG void net_stats_add_tx(size_t bytes);
void net_stats_add_rx(size_t bytes);
struct net_ssl_openssl struct net_ssl_openssl
{ {
SSL* ssl; SSL* ssl;
BIO* bio;
enum ssl_state state; enum ssl_state state;
uint32_t flags; uint32_t flags;
BIO* biow; size_t bytes_rx;
BIO* bior; size_t bytes_tx;
}; };
struct net_context_openssl struct net_context_openssl
@@ -52,6 +54,44 @@ const char* net_ssl_get_provider()
return OPENSSL_VERSION_TEXT; return OPENSSL_VERSION_TEXT;
} }
int net_ssl_library_init()
{
LOG_TRACE("Initializing OpenSSL...");
SSL_library_init();
SSL_load_error_strings();
return 1;
}
int net_ssl_library_shutdown()
{
ERR_clear_error();
ERR_remove_state(0);
ENGINE_cleanup();
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
// sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
return 1;
}
static void add_io_stats(struct net_ssl_openssl* handle)
{
if (handle->bio->num_read > handle->bytes_rx)
{
net_stats_add_rx(handle->bio->num_read - handle->bytes_rx);
handle->bytes_rx = handle->bio->num_read;
}
if (handle->bio->num_write > handle->bytes_tx)
{
net_stats_add_tx(handle->bio->num_write - handle->bytes_tx);
handle->bytes_tx = handle->bio->num_write;
}
}
/** /**
* Create a new SSL context. * Create a new SSL context.
@@ -65,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;
@@ -161,9 +208,7 @@ ssize_t net_con_ssl_connect(struct net_connection* con)
handle->state = tls_st_connecting; handle->state = tls_st_connecting;
ret = SSL_connect(handle->ssl); ret = SSL_connect(handle->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_connect() ret=%d", ret); LOG_PROTO("SSL_connect() ret=%d", ret);
#endif /* NETWORK_DUMP_DEBUG */
if (ret > 0) if (ret > 0)
{ {
@@ -190,8 +235,7 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode
return -1; return -1;
} }
SSL_set_fd(handle->ssl, con->sd); SSL_set_fd(handle->ssl, con->sd);
handle->bior = SSL_get_rbio(handle->ssl); handle->bio = SSL_get_rbio(handle->ssl);
handle->biow = SSL_get_wbio(handle->ssl);
con->ssl = (struct ssl_handle*) handle; con->ssl = (struct ssl_handle*) handle;
return net_con_ssl_accept(con); return net_con_ssl_accept(con);
} }
@@ -199,8 +243,7 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode
{ {
handle->ssl = SSL_new(SSL_CTX_new(TLSv1_method())); handle->ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
SSL_set_fd(handle->ssl, con->sd); SSL_set_fd(handle->ssl, con->sd);
handle->bior = SSL_get_rbio(handle->ssl); handle->bio = SSL_get_rbio(handle->ssl);
handle->biow = SSL_get_wbio(handle->ssl);
con->ssl = (struct ssl_handle*) handle; con->ssl = (struct ssl_handle*) handle;
return net_con_ssl_connect(con); return net_con_ssl_connect(con);
} }
@@ -215,6 +258,7 @@ ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len)
ERR_clear_error(); ERR_clear_error();
ssize_t ret = SSL_write(handle->ssl, buf, len); ssize_t ret = SSL_write(handle->ssl, buf, len);
add_io_stats(handle);
LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret > 0) if (ret > 0)
{ {
@@ -237,6 +281,7 @@ ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len)
ERR_clear_error(); ERR_clear_error();
ret = SSL_read(handle->ssl, buf, len); ret = SSL_read(handle->ssl, buf, len);
add_io_stats(handle);
LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret); LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret > 0) if (ret > 0)
{ {
@@ -303,3 +348,4 @@ void net_ssl_callback(struct net_connection* con, int events)
#endif /* SSL_USE_OPENSSL */ #endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */

View File

@@ -50,6 +50,12 @@ struct ssl_context_handle;
*/ */
extern const char* net_ssl_get_provider(); extern const char* net_ssl_get_provider();
/**
* return 0 if error, 1 on success.
*/
extern int net_ssl_library_init();
extern int net_ssl_library_shutdown();
/** /**
* Create a new SSL context. * Create a new SSL context.
*/ */
@@ -91,11 +97,8 @@ extern void net_ssl_callback(struct net_connection* con, int events);
extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, struct ssl_context_handle* ssl_ctx); extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, struct ssl_context_handle* ssl_ctx);
extern SSL* net_con_get_ssl(struct net_connection* con);
#ifdef SSL_USE_OPENSSL
extern void net_con_set_ssl(struct net_connection* con, SSL*);
#endif // SSL_USE_OPENSSL
extern int net_con_is_ssl(struct net_connection* con); extern int net_con_is_ssl(struct net_connection* con);
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
#endif /* HAVE_UHUB_NETWORK_TLS_H */ #endif /* HAVE_UHUB_NETWORK_TLS_H */

View File

@@ -0,0 +1,60 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "plugin_api/handle.h"
#include "util/memory.h"
static plugin_st on_search_result(struct plugin_handle* plugin, struct plugin_user* from, struct plugin_user* to, const char* search_data)
{
if (to->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
static plugin_st on_search(struct plugin_handle* plugin, struct plugin_user* user, const char* search_data)
{
// Registered users are allowed to search.
if (user->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
static plugin_st on_p2p_connect(struct plugin_handle* plugin, struct plugin_user* from, struct plugin_user* to)
{
if (from->credentials >= auth_cred_user)
return st_default;
return st_deny;
}
int plugin_register(struct plugin_handle* plugin, const char* config)
{
PLUGIN_INITIALIZE(plugin, "No guest downloading", "0.1", "This plug-in only allows registered users to search and initiate transfers.");
plugin->ptr = NULL;
plugin->funcs.on_search = on_search;
plugin->funcs.on_search_result = on_search_result;
plugin->funcs.on_p2p_connect = on_p2p_connect;
// plugin->funcs.on_p2p_revconnect = on_p2p_connect;
return 0;
}
int plugin_unregister(struct plugin_handle* plugin)
{
return 0;
}

View File

@@ -34,6 +34,7 @@
#ifndef WINSOCK #ifndef WINSOCK
#define WINSOCK #define WINSOCK
#endif #endif
#define WINTHREAD_SUPPORT 1
#endif #endif
#if defined(__CYGWIN__) || defined(__MINGW32__) #if defined(__CYGWIN__) || defined(__MINGW32__)
@@ -113,23 +114,29 @@
#define uhub_assert assert #define uhub_assert assert
#ifdef __linux__ #ifdef __linux__
#define POSIX_THREAD_SUPPORT
#define USE_EPOLL #define USE_EPOLL
#include <sys/epoll.h> #include <sys/epoll.h>
#endif #endif
#ifdef BSD_LIKE #ifdef BSD_LIKE
#define POSIX_THREAD_SUPPORT
/* /*
#define USE_KQUEUE #define USE_KQUEUE
#include <sys/event.h> #include <sys/event.h>
*/ */
#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>
#endif #endif
#if defined(BSD_LIKE) || defined(__sun__) #if ( defined(BSD_LIKE) && !defined(__FreeBSD_kernel__) ) || defined(__sun__)
#undef HAVE_STRNDUP #undef HAVE_STRNDUP
#undef HAVE_MEMMEM #undef HAVE_MEMMEM
#endif #endif
@@ -279,6 +286,10 @@ typedef unsigned __int64 uint64_t;
#define NEED_GETOPT #define NEED_GETOPT
#endif #endif
#ifdef POSIX_THREAD_SUPPORT
#include <pthread.h>
#endif
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER) #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER)
#define PLUGIN_API __declspec(dllexport) #define PLUGIN_API __declspec(dllexport)
#else #else

View File

@@ -46,6 +46,13 @@ enum ADC_client_flags
cflag_pipe = 4, cflag_pipe = 4,
}; };
struct ADC_client_address
{
enum Protocol { ADC, ADCS } protocol;
char* hostname;
uint16_t port;
};
struct ADC_client struct ADC_client
{ {
sid_t sid; sid_t sid;
@@ -59,8 +66,9 @@ struct ADC_client
size_t timeout; size_t timeout;
struct net_connection* con; struct net_connection* con;
struct net_timer* timer; struct net_timer* timer;
struct sockaddr_in addr; struct sockaddr_storage addr;
char* hub_address; struct net_connect_handle* connect_job;
struct ADC_client_address address;
char* nick; char* nick;
char* desc; char* desc;
int flags; int flags;
@@ -160,9 +168,6 @@ static void event_callback(struct net_connection* con, int events, void *arg)
client->callback(client, ADC_CLIENT_DISCONNECTED, 0); client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
return; return;
} }
if (events & NET_EVENT_WRITE)
ADC_client_connect(client, 0);
break; break;
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
@@ -493,7 +498,8 @@ void ADC_client_send(struct ADC_client* client, struct adc_message* msg)
void ADC_client_send_info(struct ADC_client* client) void ADC_client_send_info(struct ADC_client* client)
{ {
ADC_TRACE; ADC_TRACE;
client->info = adc_msg_construct_source(ADC_CMD_BINF, client->sid, 64); client->info = adc_msg_construct_source(ADC_CMD_BINF, client->sid, 96);
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_NICK, client->nick); adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_NICK, client->nick);
@@ -502,9 +508,20 @@ void ADC_client_send_info(struct ADC_client* client)
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_DESCRIPTION, client->desc); adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_DESCRIPTION, client->desc);
} }
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT, PRODUCT "/" VERSION); adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT, PRODUCT " " VERSION);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_UPLOAD_SLOTS, 0);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_SHARED_SIZE, 0);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_SHARED_FILES, 0);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_NORMAL, 1);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_REGISTER, 0);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_COUNT_HUB_OPERATOR, 0);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_DOWNLOAD_SPEED, 5 * 1024 * 1024);
adc_msg_add_named_argument_int(client->info, ADC_INF_FLAG_UPLOAD_SPEED, 10 * 1024 * 1024);
adc_cid_pid(client); adc_cid_pid(client);
ADC_client_send(client, client->info); ADC_client_send(client, client->info);
} }
@@ -514,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);
@@ -541,31 +553,46 @@ void ADC_client_destroy(struct ADC_client* client)
adc_msg_free(client->info); adc_msg_free(client->info);
hub_free(client->nick); hub_free(client->nick);
hub_free(client->desc); hub_free(client->desc);
hub_free(client->hub_address); hub_free(client->address.hostname);
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->hub_address) if (client->state == ps_none)
{ {
if (!ADC_client_parse_address(client, address)) if (!ADC_client_parse_address(client, address))
return 0; return 0;
client->callback(client, ADC_CLIENT_CONNECTING, 0);
} }
int ret = net_connect(net_con_get_sd(client->con), (struct sockaddr*) &client->addr, sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
ADC_client_on_connected(client);
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
ADC_client_set_state(client, ps_conn); ADC_client_set_state(client, ps_conn);
} client->connect_job = net_con_connect(client->address.hostname, client->address.port, connect_callback, client);
else if (!client->connect_job)
{ {
ADC_client_on_disconnected(client); ADC_client_on_disconnected(client);
return 0; return 0;
@@ -573,6 +600,7 @@ int ADC_client_connect(struct ADC_client* client, const char* address)
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;
@@ -588,10 +616,12 @@ static void ADC_client_on_connected(struct ADC_client* client)
else else
#endif #endif
{ {
struct adc_message* handshake = adc_msg_create(ADC_HANDSHAKE);
net_con_update(client->con, NET_EVENT_READ); net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_CONNECTED, 0); client->callback(client, ADC_CLIENT_CONNECTED, 0);
ADC_client_send(client, adc_msg_create(ADC_HANDSHAKE)); ADC_client_send(client, handshake);
ADC_client_set_state(client, ps_protocol); ADC_client_set_state(client, ps_protocol);
adc_msg_free(handshake);
} }
} }
@@ -599,11 +629,13 @@ static void ADC_client_on_connected(struct ADC_client* client)
static void ADC_client_on_connected_ssl(struct ADC_client* client) static void ADC_client_on_connected_ssl(struct ADC_client* client)
{ {
ADC_TRACE; ADC_TRACE;
struct adc_message* handshake = adc_msg_create(ADC_HANDSHAKE);
client->callback(client, ADC_CLIENT_SSL_OK, 0); client->callback(client, ADC_CLIENT_SSL_OK, 0);
client->callback(client, ADC_CLIENT_CONNECTED, 0); client->callback(client, ADC_CLIENT_CONNECTED, 0);
net_con_update(client->con, NET_EVENT_READ); net_con_update(client->con, NET_EVENT_READ);
ADC_client_send(client, adc_msg_create(ADC_HANDSHAKE)); ADC_client_send(client, handshake);
ADC_client_set_state(client, ps_protocol); ADC_client_set_state(client, ps_protocol);
adc_msg_free(handshake);
} }
#endif #endif
@@ -635,16 +667,13 @@ void ADC_client_disconnect(struct ADC_client* client)
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;
const char* hub_address = arg;
char* split; char* split;
int ssl = 0; int ssl = 0;
struct hostent* dns;
struct in_addr* addr;
if (!arg) if (!arg)
return 0; return 0;
client->hub_address = hub_strdup(arg);
/* Minimum length of a valid address */ /* Minimum length of a valid address */
if (strlen(arg) < 9) if (strlen(arg) < 9)
return 0; return 0;
@@ -653,39 +682,30 @@ static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
if (!strncmp(arg, "adc://", 6)) if (!strncmp(arg, "adc://", 6))
{ {
client->flags &= ~cflag_ssl; client->flags &= ~cflag_ssl;
client->address.protocol = ADC;
} }
else if (!strncmp(arg, "adcs://", 7)) else if (!strncmp(arg, "adcs://", 7))
{ {
client->flags |= cflag_ssl; client->flags |= cflag_ssl;
ssl = 1; ssl = 1;
client->address.protocol = ADCS;
} }
else else
return 0; return 0;
/* Split hostname and port (if possible) */ /* Split hostname and port (if possible) */
split = strrchr(client->hub_address + 6 + ssl, ':'); hub_address = arg + 6 + ssl;
split = strrchr(hub_address, ':');
if (split == 0 || strlen(split) < 2 || strlen(split) > 6) if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
return 0; return 0;
/* Ensure port number is valid */ /* Ensure port number is valid */
int port = strtol(split+1, NULL, 10); client->address.port = strtol(split+1, NULL, 10);
if (port <= 0 || port > 65535) if (client->address.port <= 0 || client->address.port > 65535)
return 0; return 0;
split[0] = 0; client->address.hostname = strndup(hub_address, &split[0] - &hub_address[0]);
/* Resolve IP address (FIXME: blocking call) */
dns = gethostbyname(client->hub_address + 6 + ssl);
if (dns)
{
addr = (struct in_addr*) dns->h_addr_list[0];
}
// Initialize the sockaddr struct.
memset(&client->addr, 0, sizeof(client->addr));
client->addr.sin_family = AF_INET;
client->addr.sin_port = htons(port);
memcpy(&client->addr.sin_addr, addr, sizeof(struct in_addr));
return 1; return 1;
} }

View File

@@ -28,6 +28,7 @@ struct ADC_client;
enum ADC_client_callback_type enum ADC_client_callback_type
{ {
ADC_CLIENT_NAME_LOOKUP = 1000,
ADC_CLIENT_CONNECTING = 1001, ADC_CLIENT_CONNECTING = 1001,
ADC_CLIENT_CONNECTED = 1002, ADC_CLIENT_CONNECTED = 1002,
ADC_CLIENT_DISCONNECTED = 1003, ADC_CLIENT_DISCONNECTED = 1003,

View File

@@ -35,7 +35,6 @@ static struct ADC_user* user_get(sid_t sid)
return user; return user;
} }
static void user_remove(const struct ADC_client_quit_reason* quit) static void user_remove(const struct ADC_client_quit_reason* quit)
{ {
struct ADC_user* user = user_get(quit->sid); struct ADC_user* user = user_get(quit->sid);
@@ -91,6 +90,10 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
{ {
switch (type) switch (type)
{ {
case ADC_CLIENT_NAME_LOOKUP:
status("Looking up hostname...");
break;
case ADC_CLIENT_CONNECTING: case ADC_CLIENT_CONNECTING:
status("Connecting..."); status("Connecting...");
break; break;
@@ -107,6 +110,9 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
status("SSL handshake."); status("SSL handshake.");
break; break;
case ADC_CLIENT_SSL_OK:
break;
case ADC_CLIENT_LOGGING_IN: case ADC_CLIENT_LOGGING_IN:
status("Logging in..."); status("Logging in...");
break; break;
@@ -155,6 +161,68 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
static int running = 1; static int running = 1;
#if !defined(WIN32)
void adm_handle_signal(int sig)
{
switch (sig)
{
case SIGINT:
LOG_INFO("Interrupted. Shutting down...");
running = 0;
break;
case SIGTERM:
LOG_INFO("Terminated. Shutting down...");
running = 0;
break;
case SIGPIPE:
break;
case SIGHUP:
break;
default:
LOG_TRACE("hub_handle_signal(): caught unknown signal: %d", signal);
running = 0;
break;
}
}
static int signals[] =
{
SIGINT, /* Interrupt the application */
SIGTERM, /* Terminate the application */
SIGPIPE, /* prevent sigpipe from kills the application */
SIGHUP, /* reload configuration */
0
};
void adm_setup_signal_handlers()
{
sigset_t sig_set;
struct sigaction act;
int i;
sigemptyset(&sig_set);
act.sa_mask = sig_set;
act.sa_flags = SA_ONSTACK | SA_RESTART;
act.sa_handler = adm_handle_signal;
for (i = 0; signals[i]; i++)
{
if (sigaction(signals[i], &act, 0) != 0)
{
LOG_ERROR("Error setting signal handler %d", signals[i]);
}
}
}
void adm_shutdown_signal_handlers()
{
}
#endif /* !WIN32 */
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
if (argc < 2) if (argc < 2)
@@ -163,6 +231,9 @@ int main(int argc, char** argv)
return 1; return 1;
} }
hub_set_log_verbosity(5);
adm_setup_signal_handlers();
struct ADC_client* client; struct ADC_client* client;
net_initialize(); net_initialize();
@@ -176,6 +247,7 @@ int main(int argc, char** argv)
ADC_client_destroy(client); ADC_client_destroy(client);
net_destroy(); net_destroy();
adm_shutdown_signal_handlers();
return 0; return 0;
} }

View File

@@ -68,12 +68,14 @@ extern "C" {
#include "util/memory.h" #include "util/memory.h"
#include "util/misc.h" #include "util/misc.h"
#include "util/tiger.h" #include "util/tiger.h"
#include "util/threads.h"
#include "adc/sid.h" #include "adc/sid.h"
#include "adc/message.h" #include "adc/message.h"
#include "network/network.h" #include "network/network.h"
#include "network/connection.h" #include "network/connection.h"
#include "network/dnsresolver.h"
#include "network/ipcalc.h" #include "network/ipcalc.h"
#include "network/timeout.h" #include "network/timeout.h"
@@ -92,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"

View File

@@ -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;
#ifdef SYSTEMD
case log_user: level = LOG_INFO; break;
#else
case log_user: level = LOG_INFO | LOG_AUTH; break; 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

View File

@@ -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 node;
}
static struct rb_node* create_node(struct rb_tree* tree, const void* key, const void* value)
{
struct rb_node* node = tree->alloc(sizeof(struct rb_node));
node->key = key;
node->value = value;
node->red = 1;
node->link[0] = 0;
node->link[1] = 0;
return node;
}
static int is_red(struct rb_node* node)
{
return node && node->red;
}
#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
{
struct rb_node *ln = node->link[0];
struct rb_node *rn = node->link[1];
/* Consecutive red links */
if (is_red(node)) {
if (is_red(ln) || is_red(rn))
{
puts("Red violation");
return 0;
}
}
lh = rb_tree_check(tree, ln);
rh = rb_tree_check(tree, rn);
/* Invalid binary search tree - not sorted correctly */
if ((ln && tree->compare(ln->key, node->key) >= 0) || (rn && tree->compare(rn->key, node->key) <= 0))
{
puts("Binary tree violation");
return 0; return 0;
} }
static struct rb_node* tree_insert(struct rb_tree* tree, const void* key, const void* value) /* Black height mismatch */
{ if ( lh != 0 && rh != 0 && lh != rh ) {
struct rb_node* node = tree->root; puts ( "Black violation" );
struct rb_node* newnode = tree->alloc(sizeof(struct rb_node)); return 0;
newnode->key = key; }
newnode->value = value;
newnode->color = RED;
/* Only count black links */
if (lh != 0 && rh != 0)
return is_red(node) ? lh : lh + 1;
else
return 0;
}
}
#endif // RB_TREE_CHECKS
while (node) static struct rb_node* rb_tree_rotate_single(struct rb_node* node, int dir)
{ {
int res = tree->compare(key, node->key); struct rb_node* other = node->link[!dir];
if (res < 0) node = node->left;
else if (res > 0) node = node->right; 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 else
{ {
/* key already exists in tree */ int dir = res < 0;
return node; node->link[dir] = rb_tree_insert_r(tree, node->link[dir], key, value);
}
}
return newnode; if (is_red(node->link[dir]))
{
if (is_red(node->link[!dir]))
{
/* Case 1 */
node->red = 1;
node->link[0]->red = 0;
node->link[1]->red = 0;
}
else
{
/* Cases 2 & 3 */
if (is_red(node->link[dir]->link[dir]))
node = rb_tree_rotate_single(node, !dir);
else if (is_red(node->link[dir]->link[!dir]))
node = rb_tree_rotate_double(node, !dir);
}
}
}
return node;
} }
@@ -102,36 +159,224 @@ struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree
{ {
struct rb_tree* tree = a(sizeof(struct rb_tree)); 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);
}

View File

@@ -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 */

149
src/util/threads.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* 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 "uhub.h"
#ifdef POSIX_THREAD_SUPPORT
struct pthread_data
{
pthread_t handle;
};
void uhub_mutex_init(uhub_mutex_t* mutex)
{
pthread_mutex_init(mutex, NULL);
}
void uhub_mutex_destroy(uhub_mutex_t* mutex)
{
pthread_mutex_destroy(mutex);
}
void uhub_mutex_lock(uhub_mutex_t* mutex)
{
pthread_mutex_lock(mutex);
}
void uhub_mutex_unlock(uhub_mutex_t* mutex)
{
pthread_mutex_unlock(mutex);
}
int uhub_mutex_trylock(uhub_mutex_t* mutex)
{
int ret = pthread_mutex_trylock(mutex);
return (ret == 0);
}
uhub_thread_t* uhub_thread_create(uhub_thread_start start, void* arg)
{
struct pthread_data* thread = (struct pthread_data*) hub_malloc_zero(sizeof(struct pthread_data));
int ret = pthread_create(&thread->handle, NULL, start, arg);
if (ret != 0)
{
hub_free(thread);
thread = NULL;
}
return thread;
}
void uhub_thread_cancel(uhub_thread_t* thread)
{
pthread_cancel(thread->handle);
}
void* uhub_thread_join(uhub_thread_t* thread)
{
void* ret = NULL;
pthread_join(thread->handle, &ret);
hub_free(thread);
return ret;
}
#endif /* POSIX_THREAD_SUPPORT */
#ifdef WINTHREAD_SUPPORT
struct winthread_data
{
uhub_thread_t* handle;
uhub_thread_start start;
void* arg;
};
static DWORD WINAPI uhub_winthread_start(void* ptr)
{
struct winthread_data* data = (struct winthread_data*) ptr;
DWORD ret = (DWORD) data->start(data->arg);
return ret;
}
void uhub_mutex_init(uhub_mutex_t* mutex)
{
InitializeCriticalSection(mutex);
}
void uhub_mutex_destroy(uhub_mutex_t* mutex)
{
DeleteCriticalSection(mutex);
}
void uhub_mutex_lock(uhub_mutex_t* mutex)
{
EnterCriticalSection(mutex);
}
void uhub_mutex_unlock(uhub_mutex_t* mutex)
{
LeaveCriticalSection(mutex);
}
int uhub_mutex_trylock(uhub_mutex_t* mutex)
{
return TryEnterCriticalSection(mutex);
}
uhub_thread_t* uhub_thread_create(uhub_thread_start start, void* arg)
{
struct winthread_data* thread = (struct winthread_data*) hub_malloc_zero(sizeof(struct winthread_data));
thread->start = start;
thread->arg = arg;
thread->handle = CreateThread(NULL, 0, uhub_winthread_start, thread, 0, 0);
return thread;
}
void uhub_thread_cancel(uhub_thread_t* thread)
{
TerminateThread(thread->handle, 0);
}
void* uhub_thread_join(uhub_thread_t* thread)
{
void* ret = NULL;
DWORD exitCode;
WaitForSingleObject(thread->handle, INFINITE);
GetExitCodeThread(thread->handle, &exitCode);
ret = &exitCode;
CloseHandle(thread->handle);
hub_free(thread);
return ret;
}
#endif /* WINTHREAD_SUPPORT */

49
src/util/threads.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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/>.
*
*/
#ifndef HAVE_UHUB_UTIL_THREADS_H
#define HAVE_UHUB_UTIL_THREADS_H
typedef void*(*uhub_thread_start)(void*) ;
#ifdef POSIX_THREAD_SUPPORT
typedef struct pthread_data uhub_thread_t;
typedef pthread_mutex_t uhub_mutex_t;
#endif
#ifdef WINTHREAD_SUPPORT
struct winthread_data;
typedef struct winthread_data uhub_thread_t;
typedef CRITICAL_SECTION uhub_mutex_t;
#endif
// Mutexes
extern void uhub_mutex_init(uhub_mutex_t* mutex);
extern void uhub_mutex_destroy(uhub_mutex_t* mutex);
extern void uhub_mutex_lock(uhub_mutex_t* mutex);
extern void uhub_mutex_unlock(uhub_mutex_t* mutex);
extern int uhub_mutex_trylock(uhub_mutex_t* mutex);
// Threads
uhub_thread_t* uhub_thread_create(uhub_thread_start start, void* arg);
void uhub_thread_cancel(uhub_thread_t* thread);
void* uhub_thread_join(uhub_thread_t* thread);
#endif /* HAVE_UHUB_UTIL_THREADS_H */