Compare commits

...

27 Commits

Author SHA1 Message Date
Jan Vidar Krey
2f830d3132 Cleaned up error handling. 2012-10-17 15:39:48 +02:00
Jan Vidar Krey
5884983a2f Return -1 as error for recv/send only to signal socket has closed, use a number < -1 for socket errors. 2012-10-17 15:02:32 +02:00
Jan Vidar Krey
c43acd97bd Fixed accept/connect state event propagation.
Also removed some unused states and flags.
2012-10-17 09:25:15 +02:00
Jan Vidar Krey
b1f2c93738 Reworked the error handling of non-blocking reads and writes.
This should prevent busy loops where the socket is makred readable
but we are really only looking for it to become writable.
2012-10-17 09:16:02 +02:00
Jan Vidar Krey
50912bdf75 More work on splitting out OpenSSL specific bits. 2012-10-15 20:39:03 +02:00
Jan Vidar Krey
f3922bb3e0 Work on splitting out OpenSSL cleanly. 2012-10-12 14:24:03 +02:00
Jan Vidar Krey
f20c42d05f Wrapped everything OpenSSL related in a SSL_USE_OPENSSL check macro. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
69603ff70f Add install make rule. 2012-10-09 14:36:14 +02:00
Jan Vidar Krey
3ea38c59af Better reporting using the !stats command. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
50292cb8c9 Update the network statistics every 10 seconds instead of 60 seconds. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
e4fc91dde1 Made the network statistics work again. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
8086d89e23 Better formatting of byte sizes. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
cc2ead8136 Use util's format_size. 2012-10-09 10:20:58 +02:00
Jan Vidar Krey
10d8157477 Added a utility function to convert an arbitrary byte size into a human readable string.
E.g. 849484 becomes "829.57 KB".
2012-10-09 10:20:12 +02:00
Jan Vidar Krey
0a7cb86014 Fixed a crash in plugin mod_chat_only. 2012-10-09 10:02:08 +02:00
Jan Vidar Krey
2e8c99b7ec Refurbished the ADC hub stress-tester tool; adcrush 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
cb6236691b Added more functionality to the ADC client test code. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
5136525abc Added API to construct ADC messages with source and destination. 2012-10-02 23:59:11 +02:00
Jan Vidar Krey
07da142e65 Only enable the C compiler (no C++ compiler required). 2012-10-05 09:09:54 +02:00
Jan Vidar Krey
aa21556600 Use correct source directory for building outside of source. 2012-10-04 22:00:30 +00:00
Tillmann Karras
16ee65422d Fix cbuffer initialization
If no data was appended, cbuf_get() would return a pointer to
uninitialized memory. Now it returns a pointer to a string of zero
length.
2012-10-03 22:40:33 +02:00
Jan Vidar Krey
f0b11dadf1 Refurbished adcrush (hub stress tester). 2012-10-03 13:51:07 +02:00
Jan Vidar Krey
61073bd304 Fix rare protocol parse error due to incorrect recv queue handling. 2012-10-03 13:49:50 +02:00
Jan Vidar Krey
20a847e1b4 Moved the ipcalc code to the network directory. 2012-10-03 12:59:05 +02:00
Jan Vidar Krey
a90807fccb Fix version auto generation. 2012-10-03 12:02:35 +02:00
Jan Vidar Krey
25c82076da Cmake fixes, build adc client and link uhub with pthread if sqlite3 is used. 2012-10-03 11:45:21 +02:00
Jan Vidar Krey
089966d918 Fix ADC client send queue. 2012-10-03 11:44:07 +02:00
39 changed files with 1053 additions and 607 deletions

View File

@@ -5,23 +5,33 @@
cmake_minimum_required (VERSION 2.8.3)
project (uhub)
project (uhub NONE)
enable_language(C)
set (UHUB_VERSION_MAJOR 0)
set (UHUB_VERSION_MINOR 4)
set (UHUB_VERSION_PATCH 1)
set (PROJECT_SOURCE_DIR "src")
set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
option(RELEASE "Release build, debug build if disabled" ON)
option(LINK_SUPPORT "Allow hub linking" OFF)
option(SSL_SUPPORT "Enable SSL support" ON)
option(USE_OPENSSL "Use OpenSSL's SSL support" OFF)
option(SQLITE_SUPPORT "Enable SQLite support" ON)
option(ADC_STRESS "Enable the stress tester client" OFF)
find_package(Git)
if (SSL_SUPPORT)
find_package(OpenSSL REQUIRED)
if (USE_OPENSSL)
find_package(OpenSSL)
else()
find_package(GnuTLS)
endif()
if (NOT GNUTLS_FOUND AND NOT OPENSSL_FOUND)
message(FATAL_ERROR "Neither OpenSSL nor GnuTLS are not found!")
endif()
endif()
if (MSVC)
@@ -39,7 +49,8 @@ set (network_SOURCES
${PROJECT_SOURCE_DIR}/network/timeout.c
${PROJECT_SOURCE_DIR}/network/timer.c
${PROJECT_SOURCE_DIR}/network/network.c
${PROJECT_SOURCE_DIR}/util/ipcalc.c
${PROJECT_SOURCE_DIR}/network/openssl.c
${PROJECT_SOURCE_DIR}/network/ipcalc.c
)
set (uhub_SOURCES
@@ -83,6 +94,7 @@ set (utils_SOURCES
set (adcclient_SOURCES
${PROJECT_SOURCE_DIR}/tools/adcclient.c
${PROJECT_SOURCE_DIR}/core/ioqueue.c
)
add_library(adc STATIC ${adc_SOURCES})
@@ -110,6 +122,10 @@ if (SQLITE_SUPPORT)
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)
@@ -132,25 +148,44 @@ target_link_libraries(uhub ${CMAKE_DL_LIBS} adc network utils)
if(UNIX)
add_library(adcclient STATIC ${adcclient_SOURCES})
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c ${adcclient_SOURCES})
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c)
target_link_libraries(uhub-admin adcclient adc network utils)
if (ADC_STRESS)
add_executable(adcrush ${PROJECT_SOURCE_DIR}/tools/adcrush.c ${adcclient_SOURCES})
target_link_libraries(adcrush adcclient adc network utils)
endif()
endif()
if(GIT_FOUND)
if(GIT_FOUND AND IS_DIRECTORY ".git")
execute_process(COMMAND ${GIT_EXECUTABLE} show -s --pretty=format:%h OUTPUT_VARIABLE UHUB_REVISION)
set (UHUB_GIT_VERSION "${UHUB_VERSION_MAJOR}.${UHUB_VERSION_MINOR}.${UHUB_VERSION_PATCH}-git-${UHUB_REVISION}")
else()
set (UHUB_GIT_VERSION "${UHUB_VERSION_MAJOR}.${UHUB_VERSION_MINOR}.${UHUB_VERSION_PATCH}-release")
endif()
if(OPENSSL_FOUND)
add_definitions(-DSSL_SUPPORT=1)
set(SSL_LIBS ${OPENSSL_LIBRARIES})
add_definitions(-DSSL_SUPPORT=1 -DSSL_USE_OPENSSL=1)
include_directories(${OPENSSL_INCLUDE_DIR})
target_link_libraries(uhub ${OPENSSL_LIBRARIES})
endif()
if (GNUTLS_FOUND)
set(SSL_LIBS ${GNUTLS_LIBRARIES})
add_definitions(-DSSL_SUPPORT=1 -DSSL_USE_GNUTLS=1 ${GNUTLS_DEFINITIONS})
include_directories(${GNUTLS_INCLUDE_DIR})
endif()
if(SSL_SUPPORT)
target_link_libraries(uhub ${SSL_LIBS})
if(UNIX)
target_link_libraries(uhub-admin ${OPENSSL_LIBRARIES})
target_link_libraries(uhub-admin ${SSL_LIBS})
endif()
target_link_libraries(mod_welcome ${SSL_LIBS})
target_link_libraries(mod_logging ${SSL_LIBS})
if (ADC_STRESS)
target_link_libraries(adcrush ${SSL_LIBS})
endif()
target_link_libraries(mod_welcome ${OPENSSL_LIBRARIES})
target_link_libraries(mod_logging ${OPENSSL_LIBRARIES})
endif()
configure_file ("${PROJECT_SOURCE_DIR}/version.h.in" "${PROJECT_SOURCE_DIR}/version.h")
@@ -160,11 +195,20 @@ if (RELEASE)
set(CMAKE_BUILD_TYPE Release)
else()
set(CMAKE_BUILD_TYPE Debug)
# add_definitions(-DDEBUG)
endif()
if (UNIX)
install( TARGETS uhub RUNTIME DESTINATION bin )
install( TARGETS mod_example mod_welcome mod_logging mod_auth_simple mod_auth_sqlite mod_chat_history mod_chat_only mod_topic DESTINATION /var/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 )
if (SQLITE_SUPPORT)
install( TARGETS uhub-passwd RUNTIME DESTINATION bin )
endif()
endif()

View File

@@ -532,9 +532,9 @@ struct adc_message* adc_msg_create(const char* line)
return adc_msg_parse(line, strlen(line));
}
extern struct adc_message* adc_msg_construct_source(fourcc_t fourcc, sid_t source, size_t size)
struct adc_message* adc_msg_construct_source(fourcc_t fourcc, sid_t source, size_t size)
{
struct adc_message* msg = adc_msg_construct(fourcc, size + 4);
struct adc_message* msg = adc_msg_construct(fourcc, size + 4 + 1);
if (!msg)
return NULL;
@@ -543,6 +543,20 @@ extern struct adc_message* adc_msg_construct_source(fourcc_t fourcc, sid_t sourc
return msg;
}
struct adc_message* adc_msg_construct_source_dest(fourcc_t fourcc, sid_t source, sid_t dest, size_t size)
{
struct adc_message* msg = adc_msg_construct(fourcc, size + 4 + 4 + 1);
if (!msg)
return NULL;
adc_msg_add_argument(msg, sid_to_string(source));
adc_msg_add_argument(msg, sid_to_string(dest));
msg->source = source;
msg->target = dest;
return msg;
}
struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size)
{
struct adc_message* msg = (struct adc_message*) msg_malloc_zero(sizeof(struct adc_message));

View File

@@ -96,6 +96,7 @@ extern struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size);
* in addition pre-allocate 'size' bytes at the end of the message.
*/
extern struct adc_message* adc_msg_construct_source(fourcc_t fourcc, sid_t source, size_t size);
extern struct adc_message* adc_msg_construct_source_dest(fourcc_t fourcc, sid_t source, sid_t dest, size_t size);
/**
* Remove a named argument from the command.

View File

@@ -557,14 +557,28 @@ static int command_stats(struct command_base* cbase, struct hub_user* user, stru
{
struct cbuffer* buf = cbuf_create(128);
struct hub_info* hub = cbase->hub;
static char rxbuf[64] = { "0 B" };
static char txbuf[64] = { "0 B" };
cbuf_append(buf, "Hub statistics: ");
cbuf_append_format(buf, PRINTF_SIZE_T "/" PRINTF_SIZE_T " users (peak %d). ", hub->users->count, hub->config->max_users, hub->users->count_peak);
format_size(hub->stats.net_rx, rxbuf, sizeof(rxbuf));
format_size(hub->stats.net_tx, txbuf, sizeof(txbuf));
cbuf_append_format(buf, "Network: tx=%s/s, rx=%s/s", txbuf, rxbuf);
#ifdef SHOW_PEAK_NET_STATS /* currently disabled */
format_size(hub->stats.net_rx_peak, rxbuf, sizeof(rxbuf));
format_size(hub->stats.net_tx_peak, txbuf, sizeof(txbuf));
cbuf_append_format(buf, ", peak_tx=%s/s, peak_rx=%s/s", txbuf, rxbuf);
#endif
format_size(hub->stats.net_rx_total, rxbuf, sizeof(rxbuf));
format_size(hub->stats.net_tx_total, txbuf, sizeof(txbuf));
cbuf_append_format(buf, ", total_tx=%s", txbuf);
cbuf_append_format(buf, ", total_rx=%s", rxbuf);
cbuf_append_format(buf, PRINTF_SIZE_T " users, peak: " PRINTF_SIZE_T ". Network (up/down): %d/%d KB/s, peak: %d/%d KB/s",
hub->users->count,
hub->users->count_peak,
(int) hub->stats.net_tx / 1024,
(int) hub->stats.net_rx / 1024,
(int) hub->stats.net_tx_peak / 1024,
(int) hub->stats.net_rx_peak / 1024);
return command_status(cbase, user, cmd, buf);
}

View File

@@ -600,6 +600,31 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message
}
}
static void hub_update_stats(struct hub_info* hub)
{
const int factor = TIMEOUT_STATS;
struct net_statistics* total;
struct net_statistics* intermediate;
net_stats_get(&intermediate, &total);
hub->stats.net_tx = (intermediate->tx / factor);
hub->stats.net_rx = (intermediate->rx / factor);
hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
hub->stats.net_tx_total = total->tx;
hub->stats.net_rx_total = total->rx;
net_stats_reset();
}
static void hub_timer_statistics(struct timeout_evt* t)
{
struct hub_info* hub = (struct hub_info*) t->ptr;
hub_update_stats(hub);
timeout_queue_reschedule(net_backend_get_timeout_queue(), hub->stats.timeout, TIMEOUT_STATS);
}
static struct net_connection* start_listening_socket(const char* bind_addr, uint16_t port, int backlog, struct hub_info* hub)
{
struct net_connection* server;
@@ -706,41 +731,25 @@ static int load_ssl_certificates(struct hub_info* hub, struct hub_config* config
{
if (config->tls_enable)
{
hub->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */
hub->ssl_ctx = SSL_CTX_new(hub->ssl_method);
/* Disable SSLv2 */
SSL_CTX_set_options(hub->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_quiet_shutdown(hub->ssl_ctx, 1);
if (SSL_CTX_use_certificate_file(hub->ssl_ctx, config->tls_certificate, SSL_FILETYPE_PEM) < 0)
hub->ctx = net_ssl_context_create();
if (ssl_load_certificate(hub->ctx, config->tls_certificate) &&
ssl_load_private_key(hub->ctx, config->tls_private_key) &&
ssl_check_private_key(hub->ctx))
{
LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
LOG_INFO("Enabling TLS (%s), using certificate: %s, private key: %s", net_ssl_get_provider(), config->tls_certificate, config->tls_private_key);
return 1;
}
if (SSL_CTX_use_PrivateKey_file(hub->ssl_ctx, config->tls_private_key, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
}
if (SSL_CTX_check_private_key(hub->ssl_ctx) != 1)
{
LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
LOG_INFO("Enabling TLS, using certificate: %s, private key: %s", config->tls_certificate, config->tls_private_key);
return 0;
}
return 1;
}
static void unload_ssl_certificates(struct hub_info* hub)
{
if (hub->ssl_ctx)
{
SSL_CTX_free(hub->ssl_ctx);
}
if (hub->ctx)
net_ssl_context_destroy(hub->ctx);
}
#endif
#endif /* SSL_SUPPORT */
struct hub_info* hub_start_service(struct hub_config* config)
{
@@ -816,6 +825,13 @@ struct hub_info* hub_start_service(struct hub_config* config)
g_hub = hub;
if (net_backend_get_timeout_queue())
{
hub->stats.timeout = hub_malloc_zero(sizeof(struct timeout_evt));
timeout_evt_initialize(hub->stats.timeout, hub_timer_statistics, hub);
timeout_queue_insert(net_backend_get_timeout_queue(), hub->stats.timeout, TIMEOUT_STATS);
}
// Start the hub command sub-system
hub->commands = command_initialize(hub);
return hub;
@@ -826,6 +842,12 @@ void hub_shutdown_service(struct hub_info* hub)
{
LOG_DEBUG("hub_shutdown_service()");
if (net_backend_get_timeout_queue())
{
timeout_queue_remove(net_backend_get_timeout_queue(), hub->stats.timeout);
hub_free(hub->stats.timeout);
}
#ifdef SSL_SUPPORT
unload_ssl_certificates(hub);
#endif

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2011, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -81,6 +81,7 @@ struct hub_stats
size_t net_rx_peak;
size_t net_tx_total;
size_t net_rx_total;
struct timeout_evt* timeout; /**<< "Timeout handler for statistics" */
};
struct hub_logout_info
@@ -115,8 +116,7 @@ struct hub_info
struct uhub_plugins* plugins; /* Plug-ins loaded for this hub instance. */
#ifdef SSL_SUPPORT
SSL_METHOD* ssl_method;
SSL_CTX* ssl_ctx;
struct ssl_context_handle* ctx;
#endif /* SSL_SUPPORT */
};

View File

@@ -141,13 +141,13 @@ void ioq_send_remove(struct ioq_send* q, struct adc_message* msg)
q->offset = 0;
}
int ioq_send_send(struct ioq_send* q, struct hub_user* user)
int ioq_send_send(struct ioq_send* q, struct net_connection* con)
{
int ret;
struct adc_message* msg = list_get_first(q->queue);
if (!msg) return 0;
uhub_assert(msg->cache && *msg->cache);
ret = net_con_send(user->connection, msg->cache + q->offset, msg->length - q->offset);
ret = net_con_send(con, msg->cache + q->offset, msg->length - q->offset);
if (ret > 0)
{

View File

@@ -60,7 +60,7 @@ extern void ioq_send_add(struct ioq_send*, struct adc_message* msg);
* Process the send queue, and send as many messages as possible.
* @returns -1 on error, 0 if unable to send more, 1 if more can be sent.
*/
extern int ioq_send_send(struct ioq_send*, struct hub_user*);
extern int ioq_send_send(struct ioq_send*, struct net_connection* con);
/**
* @returns 1 if send queue is empty, 0 otherwise.

View File

@@ -55,7 +55,7 @@ int handle_net_read(struct hub_user* user)
while ((pos = memchr(start, '\n', remaining)))
{
lastPos = pos;
lastPos = pos+1;
pos[0] = '\0';
#ifdef DEBUG_SENDQ
@@ -109,7 +109,7 @@ int handle_net_write(struct hub_user* user)
int ret = 0;
while (ioq_send_get_bytes(user->send_queue))
{
ret = ioq_send_send(user->send_queue, user);
ret = ioq_send_send(user->send_queue, user->connection);
if (ret <= 0)
break;
}

View File

@@ -85,7 +85,7 @@ static void probe_net_event(struct net_connection* con, int events, void *arg)
{
probe->connection = 0;
}
net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ssl_ctx);
net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ctx);
}
else
{

View File

@@ -38,42 +38,6 @@ static void clear_user_list_callback(void* ptr)
}
}
#ifdef STATS_SUPPORT
void uman_update_stats(struct hub_user_manager* users)
{
const int factor = TIMEOUT_STATS;
struct net_statistics* total;
struct net_statistics* intermediate;
net_stats_get(&intermediate, &total);
users->stats.net_tx = (intermediate->tx / factor);
users->stats.net_rx = (intermediate->rx / factor);
users->stats.net_tx_peak = MAX(users->stats.net_tx, users->stats.net_tx_peak);
users->stats.net_rx_peak = MAX(users->stats.net_rx, users->stats.net_rx_peak);
users->stats.net_tx_total = total->tx;
users->stats.net_rx_total = total->rx;
net_stats_reset();
}
void uman_print_stats(struct hub_user_manager* users)
{
LOG_INFO("Statistics users=" PRINTF_SIZE_T " (peak_users=" PRINTF_SIZE_T "), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
users->users->count,
users->users->count_peak,
(int) users->stats.net_tx / 1024,
(int) users->stats.net_rx / 1024,
(int) users->stats.net_tx_peak / 1024,
(int) users->stats.net_rx_peak / 1024);
}
static void timer_statistics(struct timeout_evt* t)
{
struct hub_user_manager* users = (struct hub_user_manager*) t->ptr;
uman_update_stats(users);
timeout_queue_reschedule(net_backend_get_timeout_queue(), users->timeout, TIMEOUT_STATS);
}
#endif // STATS_SUPPORT
struct hub_user_manager* uman_init()
{
@@ -91,15 +55,6 @@ struct hub_user_manager* uman_init()
return NULL;
}
#ifdef STATS_SUPPORT
if (net_backend_get_timeout_queue())
{
users->timeout = hub_malloc_zero(sizeof(struct timeout_evt));
timeout_evt_initialize(users->timeout, timer_statistics, hub);
timeout_queue_insert(net_backend_get_timeout_queue(), users->timeout, TIMEOUT_STATS);
}
#endif // STATS_SUPPORT
return users;
}
@@ -109,14 +64,6 @@ int uman_shutdown(struct hub_user_manager* users)
if (!users)
return -1;
#ifdef STATS_SUPPORT
if (net_backend_get_timeout_queue())
{
timeout_queue_remove(net_backend_get_timeout_queue(), users->timeout);
hub_free(users->timeout);
}
#endif
if (users->list)
{
list_clear(users->list, &clear_user_list_callback);

View File

@@ -28,9 +28,6 @@ struct hub_user_manager
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct linked_list* list; /**<< "Contains all logged in users" */
#ifdef STATS_SUPPORT
struct timeout_evt* timeout; /**<< "Timeout handler for statistics" */
#endif
};
/**

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -181,11 +181,8 @@ void net_con_close(struct net_connection* con)
#ifdef SSL_SUPPORT
if (con->ssl)
{
SSL_shutdown(con->ssl);
SSL_clear(con->ssl);
}
#endif
net_ssl_shutdown(con);
#endif /* SSL_SUPPORT */
net_close(con->sd);
con->sd = -1;

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -20,11 +20,10 @@
#define NET_WANT_READ NET_EVENT_READ
#define NET_WANT_WRITE NET_EVENT_WRITE
#define NET_WANT_ACCEPT NET_EVENT_READ
#define NET_WANT_SSL_READ 0x0010
#define NET_WANT_SSL_WRITE 0x0020
#define NET_WANT_SSL_ACCEPT 0x0040
#define NET_WANT_SSL_CONNECT 0x0080
#define NET_WANT_SSL_X509_LOOKUP 0x0100
#define NET_SSL_ANY NET_WANT_SSL_READ | NET_WANT_SSL_WRITE | NET_WANT_SSL_ACCEPT | NET_WANT_SSL_CONNECT | NET_WANT_SSL_X509_LOOKUP
struct ssl_handle; /* abstract type */
#define NET_CLEANUP 0x8000
@@ -36,9 +35,7 @@
struct timeout_evt* timeout; /** timeout event handler */
#define NET_CON_STRUCT_SSL \
SSL* ssl; /** SSL handle */ \
uint32_t ssl_state; /** SSL state */ \
size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ \
struct ssl_handle* ssl; /** SSL handle */
#ifdef SSL_SUPPORT
#define NET_CON_STRUCT_COMMON \

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -20,132 +20,23 @@
#include "uhub.h"
#include "network/common.h"
#ifdef SSL_SUPPORT
enum uhub_tls_state
{
tls_st_none,
tls_st_error,
tls_st_accepting,
tls_st_connecting,
tls_st_connected,
tls_st_disconnecting,
};
static int handle_openssl_error(struct net_connection* con, int ret)
{
uhub_assert(con);
int error = SSL_get_error(con->ssl, ret);
switch (error)
{
case SSL_ERROR_ZERO_RETURN:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error);
con->ssl_state = tls_st_error;
return -1;
case SSL_ERROR_WANT_READ:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error);
con->flags |= NET_WANT_SSL_READ;
net_con_update(con, NET_EVENT_READ);
return 0;
case SSL_ERROR_WANT_WRITE:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error);
con->flags |= NET_WANT_SSL_WRITE;
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE);
return 0;
case SSL_ERROR_SYSCALL:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error);
/* if ret == 0, connection closed, if ret == -1, check with errno */
if (ret == 0)
return -1;
else
return -net_error();
case SSL_ERROR_SSL:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error);
/* internal openssl error */
con->ssl_state = tls_st_error;
return -1;
}
return -1;
}
ssize_t net_con_ssl_accept(struct net_connection* con)
{
uhub_assert(con);
con->ssl_state = tls_st_accepting;
ssize_t ret = SSL_accept(con->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_accept() ret=%d", ret);
#endif
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
con->ssl_state = tls_st_connected;
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
}
ssize_t net_con_ssl_connect(struct net_connection* con)
{
uhub_assert(con);
con->ssl_state = tls_st_connecting;
ssize_t ret = SSL_connect(con->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_connect() ret=%d", ret);
#endif
if (ret > 0)
{
con->ssl_state = tls_st_connected;
net_con_update(con, NET_EVENT_READ);
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
}
ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, SSL_CTX* ssl_ctx)
{
uhub_assert(con);
SSL* ssl = 0;
if (ssl_mode == net_con_ssl_mode_server)
{
ssl = SSL_new(ssl_ctx);
if (!ssl)
{
LOG_ERROR("Unable to create new SSL stream\n");
return -1;
}
SSL_set_fd(ssl, con->sd);
net_con_set_ssl(con, ssl);
return net_con_ssl_accept(con);
}
else
{
ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
SSL_set_fd(ssl, con->sd);
net_con_set_ssl(con, ssl);
return net_con_ssl_connect(con);
}
}
#endif /* SSL_SUPPORT */
#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()
{
int err = net_error();
return
#ifdef WINSOCK
err == WSAEWOULDBLOCK
#else
err == EWOULDBLOCK
#endif
|| err == EINTR;
}
ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{
int ret;
@@ -156,13 +47,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL);
if (ret == -1)
{
if (
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
if (is_blocked_or_interrupted())
return 0;
return -1;
}
@@ -170,19 +55,9 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
}
else
{
con->write_len = len;
ret = SSL_write(con->ssl, buf, len);
LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret <= 0)
{
return handle_openssl_error(con, ret);
}
else
{
net_stats_add_tx(ret);
}
ret = net_ssl_send(con, buf, len);
}
#endif
#endif /* SSL_SUPPORT */
return ret;
}
@@ -190,19 +65,13 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{
int ret;
#ifdef SSL_SUPPORT
if (!net_con_is_ssl(con))
if (!con->ssl)
{
#endif
ret = net_recv(con->sd, buf, len, 0);
if (ret == -1)
{
if (
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
if (is_blocked_or_interrupted())
return 0;
return -net_error();
}
@@ -214,22 +83,9 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
}
else
{
if (con->ssl_state == tls_st_error)
return -1;
ret = SSL_read(con->ssl, buf, len);
LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
net_stats_add_rx(ret);
}
else
{
return handle_openssl_error(con, ret);
}
ret = net_ssl_recv(con, buf, len);
}
#endif
#endif /* SSL_SUPPORT */
return ret;
}
@@ -238,13 +94,7 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
int ret = net_recv(con->sd, buf, len, MSG_PEEK);
if (ret == -1)
{
if (
#ifdef WINSOCK
net_error() == WSAEWOULDBLOCK
#else
net_error() == EWOULDBLOCK
#endif
|| net_error() == EINTR)
if (is_blocked_or_interrupted())
return 0;
return -net_error();
}
@@ -254,19 +104,10 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
}
#ifdef SSL_SUPPORT
int net_con_is_ssl(struct net_connection* con)
{
return con->ssl != 0;
}
SSL* net_con_get_ssl(struct net_connection* con)
{
return con->ssl;
}
void net_con_set_ssl(struct net_connection* con, SSL* ssl)
{
con->ssl = ssl;
return !!con->ssl;
}
#endif /* SSL_SUPPORT */
@@ -283,7 +124,8 @@ void* net_con_get_ptr(struct net_connection* con)
void net_con_destroy(struct net_connection* con)
{
#ifdef SSL_SUPPORT
SSL_free(con->ssl);
if (con->ssl)
net_ssl_destroy(con);
#endif
hub_free(con);
}
@@ -301,62 +143,10 @@ void net_con_callback(struct net_connection* con, int events)
}
#ifdef SSL_SUPPORT
if (!con->ssl)
{
if (con->ssl)
net_ssl_callback(con, events);
else
#endif
con->callback(con, events, con->ptr);
#ifdef SSL_SUPPORT
}
else
{
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_con_event: events=%d, con=%p, state=%d", events, con, con->ssl_state);
#endif
switch (con->ssl_state)
{
case tls_st_none:
con->callback(con, events, con->ptr);
break;
case tls_st_error:
con->callback(con, NET_EVENT_READ, con->ptr);
break;
case tls_st_accepting:
if (net_con_ssl_accept(con) < 0)
{
con->callback(con, NET_EVENT_READ, con->ptr);
}
break;
case tls_st_connecting:
if (net_con_ssl_connect(con) < 0)
{
con->callback(con, NET_EVENT_READ, con->ptr);
}
break;
case tls_st_connected:
LOG_PROTO("tls_st_connected, events=%s%s, ssl_flags=%s%s", (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), con->flags & NET_WANT_SSL_READ ? "R" : "", con->flags & NET_WANT_SSL_WRITE ? "W" : "");
if (events & NET_EVENT_WRITE && con->flags & NET_WANT_SSL_READ)
{
con->callback(con, events & NET_EVENT_READ, con->ptr);
return;
}
if (events & NET_EVENT_READ && con->flags & NET_WANT_SSL_WRITE)
{
con->callback(con, events & NET_EVENT_READ, con->ptr);
return;
}
con->callback(con, events, con->ptr);
break;
case tls_st_disconnecting:
return;
}
}
#endif
}

View File

@@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "uhub.h"
#include "network/common.h"
#include "network/backend.h"
#include "network/tls.h"
#define NET_EVENT_TIMEOUT 0x0001
#define NET_EVENT_READ 0x0002
@@ -83,29 +84,5 @@ extern ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len);
extern void net_con_set_timeout(struct net_connection* con, int seconds);
extern void net_con_clear_timeout(struct net_connection* con);
#ifdef SSL_SUPPORT
/**
* Start SSL_accept()
*/
extern ssize_t net_con_ssl_accept(struct net_connection*);
/**
* Start SSL_connect()
*/
extern ssize_t net_con_ssl_connect(struct net_connection*);
enum net_con_ssl_mode
{
net_con_ssl_mode_server,
net_con_ssl_mode_client,
};
extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx);
extern int net_con_is_ssl(struct net_connection* con);
extern SSL* net_con_get_ssl(struct net_connection* con);
extern void net_con_set_ssl(struct net_connection* con, SSL*);
#endif /* SSL_SUPPORT */
#endif /* HAVE_UHUB_NETWORK_CONNECTION_H */

View File

@@ -59,9 +59,11 @@ int net_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;
@@ -100,10 +102,12 @@ int net_destroy()
net_backend_shutdown();
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */
#ifdef WINSOCK
WSACleanup();

View File

@@ -31,6 +31,7 @@ struct net_statistics
};
struct net_socket_t;
struct ip_addr_encap;
/**
* Initialize the socket monitor subsystem.

305
src/network/openssl.c Normal file
View File

@@ -0,0 +1,305 @@
/*
* 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"
#include "network/common.h"
#include "network/tls.h"
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
#define NETWORK_DUMP_DEBUG
struct net_ssl_openssl
{
SSL* ssl;
enum ssl_state state;
uint32_t flags;
BIO* biow;
BIO* bior;
};
struct net_context_openssl
{
SSL_METHOD* ssl_method;
SSL_CTX* ssl_ctx;
};
static struct net_ssl_openssl* get_handle(struct net_connection* con)
{
uhub_assert(con);
return (struct net_ssl_openssl*) con->ssl;
}
const char* net_ssl_get_provider()
{
return OPENSSL_VERSION_TEXT;
}
/**
* Create a new SSL context.
*/
struct ssl_context_handle* net_ssl_context_create()
{
struct net_context_openssl* ctx = (struct net_context_openssl*) hub_malloc_zero(sizeof(struct net_context_openssl));
ctx->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */
ctx->ssl_ctx = SSL_CTX_new(ctx->ssl_method);
/* Disable SSLv2 */
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_quiet_shutdown(ctx->ssl_ctx, 1);
return (struct ssl_context_handle*) ctx;
}
extern void net_ssl_context_destroy(struct ssl_context_handle* ctx_)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
SSL_CTX_free(ctx->ssl_ctx);
hub_free(ctx);
}
int ssl_load_certificate(struct ssl_context_handle* ctx_, const char* pem_file)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem_file, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
return 1;
}
int ssl_load_private_key(struct ssl_context_handle* ctx_, const char* pem_file)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem_file, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
return 1;
}
int ssl_check_private_key(struct ssl_context_handle* ctx_)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1)
{
LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
return 1;
}
static int handle_openssl_error(struct net_connection* con, int ret, enum ssl_state forced_rwstate)
{
struct net_ssl_openssl* handle = get_handle(con);
int err = SSL_get_error(handle->ssl, ret);
switch (err)
{
case SSL_ERROR_ZERO_RETURN:
// Not really an error, but SSL was shut down.
return -1;
case SSL_ERROR_WANT_READ:
handle->state = forced_rwstate;
net_con_update(con, NET_EVENT_READ);
return 0;
case SSL_ERROR_WANT_WRITE:
handle->state = forced_rwstate;
net_con_update(con, NET_EVENT_WRITE);
return 0;
case SSL_ERROR_SYSCALL:
handle->state = tls_st_error;
return -2;
}
}
ssize_t net_con_ssl_accept(struct net_connection* con)
{
struct net_ssl_openssl* handle = get_handle(con);
handle->state = tls_st_accepting;
ssize_t ret;
ret = SSL_accept(handle->ssl);
LOG_PROTO("SSL_accept() ret=%d", ret);
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
handle->state = tls_st_connected;
return ret;
}
return handle_openssl_error(con, ret, tls_st_accepting);
}
ssize_t net_con_ssl_connect(struct net_connection* con)
{
struct net_ssl_openssl* handle = get_handle(con);
ssize_t ret;
handle->state = tls_st_connecting;
ret = SSL_connect(handle->ssl);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_connect() ret=%d", ret);
#endif /* NETWORK_DUMP_DEBUG */
if (ret > 0)
{
handle->state = tls_st_connected;
net_con_update(con, NET_EVENT_READ);
return ret;
}
return handle_openssl_error(con, ret, tls_st_connecting);
}
ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, struct ssl_context_handle* ssl_ctx)
{
uhub_assert(con);
struct net_context_openssl* ctx = (struct net_context_openssl*) ssl_ctx;
struct net_ssl_openssl* handle = (struct net_ssl_openssl*) hub_malloc_zero(sizeof(struct net_ssl_openssl));
if (ssl_mode == net_con_ssl_mode_server)
{
handle->ssl = SSL_new(ctx->ssl_ctx);
if (!handle->ssl)
{
LOG_ERROR("Unable to create new SSL stream\n");
return -1;
}
SSL_set_fd(handle->ssl, con->sd);
handle->bior = SSL_get_rbio(handle->ssl);
handle->biow = SSL_get_wbio(handle->ssl);
con->ssl = (struct ssl_handle*) handle;
return net_con_ssl_accept(con);
}
else
{
handle->ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
SSL_set_fd(handle->ssl, con->sd);
handle->bior = SSL_get_rbio(handle->ssl);
handle->biow = SSL_get_wbio(handle->ssl);
con->ssl = (struct ssl_handle*) handle;
return net_con_ssl_connect(con);
}
}
ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len)
{
struct net_ssl_openssl* handle = get_handle(con);
uhub_assert(handle->state == tls_st_connected || handle->state == tls_st_need_write);
ERR_clear_error();
ssize_t ret = SSL_write(handle->ssl, buf, len);
LOG_PROTO("SSL_write(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret > 0)
{
handle->state = tls_st_connected;
return ret;
}
return handle_openssl_error(con, ret, tls_st_need_write);
}
ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len)
{
struct net_ssl_openssl* handle = get_handle(con);
ssize_t ret;
if (handle->state == tls_st_error)
return -2;
uhub_assert(handle->state == tls_st_connected || handle->state == tls_st_need_read);
ERR_clear_error();
ret = SSL_read(handle->ssl, buf, len);
LOG_PROTO("SSL_read(con=%p, buf=%p, len=" PRINTF_SIZE_T ") => %d", con, buf, len, ret);
if (ret > 0)
{
handle->state = tls_st_connected;
return ret;
}
return handle_openssl_error(con, ret, tls_st_need_read);
}
void net_ssl_shutdown(struct net_connection* con)
{
struct net_ssl_openssl* handle = get_handle(con);
SSL_shutdown(handle->ssl);
SSL_clear(handle->ssl);
}
void net_ssl_destroy(struct net_connection* con)
{
struct net_ssl_openssl* handle = get_handle(con);
SSL_free(handle->ssl);
}
void net_ssl_callback(struct net_connection* con, int events)
{
struct net_ssl_openssl* handle = get_handle(con);
switch (handle->state)
{
case tls_st_none:
con->callback(con, events, con->ptr);
break;
case tls_st_error:
con->callback(con, NET_EVENT_READ, con->ptr);
break;
case tls_st_accepting:
if (net_con_ssl_accept(con) != 0)
con->callback(con, NET_EVENT_READ, con->ptr);
break;
case tls_st_connecting:
if (net_con_ssl_connect(con) != 0)
con->callback(con, NET_EVENT_READ, con->ptr);
break;
case tls_st_need_read:
con->callback(con, NET_EVENT_READ, con->ptr);
break;
case tls_st_need_write:
con->callback(con, NET_EVENT_WRITE, con->ptr);
break;
case tls_st_connected:
con->callback(con, events, con->ptr);
break;
case tls_st_disconnecting:
return;
}
}
#endif /* SSL_USE_OPENSSL */
#endif /* SSL_SUPPORT */

101
src/network/tls.h Normal file
View File

@@ -0,0 +1,101 @@
/*
* 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_NETWORK_TLS_H
#define HAVE_UHUB_NETWORK_TLS_H
#include "uhub.h"
#ifdef SSL_SUPPORT
enum ssl_state
{
tls_st_none,
tls_st_error,
tls_st_accepting,
tls_st_connecting,
tls_st_connected,
tls_st_need_read, /* special case of connected */
tls_st_need_write, /* special case of connected */
tls_st_disconnecting,
};
enum net_con_ssl_mode
{
net_con_ssl_mode_server,
net_con_ssl_mode_client,
};
struct ssl_context_handle;
/**
* Returns a string describing the TLS/SSL provider information
*/
extern const char* net_ssl_get_provider();
/**
* Create a new SSL context.
*/
extern struct ssl_context_handle* net_ssl_context_create();
extern void net_ssl_context_destroy(struct ssl_context_handle* ctx);
/**
* Return 0 on error, 1 otherwise.
*/
extern int ssl_load_certificate(struct ssl_context_handle* ctx, const char* pem_file);
/**
* Return 0 on error, 1 otherwise.
*/
extern int ssl_load_private_key(struct ssl_context_handle* ctx, const char* pem_file);
/**
* Return 0 if private key does not match certificate, 1 if everything is OK.
*/
extern int ssl_check_private_key(struct ssl_context_handle* ctx);
/**
* Start SSL_accept()
*/
extern ssize_t net_con_ssl_accept(struct net_connection*);
/**
* Start SSL_connect()
*/
extern ssize_t net_con_ssl_connect(struct net_connection*);
extern ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len);
extern ssize_t net_ssl_recv(struct net_connection* con, void* buf, size_t len);
extern void net_ssl_shutdown(struct net_connection* con);
extern void net_ssl_destroy(struct net_connection* con);
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 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);
#endif /* SSL_SUPPORT */
#endif /* HAVE_UHUB_NETWORK_TLS_H */

View File

@@ -26,7 +26,7 @@
#include "system.h"
#include "util/credentials.h"
#include "util/ipcalc.h"
#include "network/ipcalc.h"
#include "plugin_api/types.h"
typedef void (*on_connection_accepted_t)(struct plugin_handle*, struct ip_addr_encap*);

View File

@@ -20,7 +20,6 @@
#include "plugin_api/handle.h"
#include "util/memory.h"
#include "util/list.h"
#include "util/ipcalc.h"
#include "util/misc.h"
#include "util/log.h"
#include "util/config_token.h"

View File

@@ -21,7 +21,6 @@
#include <sqlite3.h>
#include "util/memory.h"
#include "util/list.h"
#include "util/ipcalc.h"
#include "util/misc.h"
#include "util/log.h"
#include "util/config_token.h"

View File

@@ -64,13 +64,13 @@ static struct user_info* get_user_info(struct chat_only_data* data, sid_t sid)
struct user_info* u;
// resize buffer if needed.
if (sid > data->max_users) // FIXME: >= ?
if (sid >= data->max_users)
{
u = hub_malloc_zero(sizeof(struct user_info) * (sid + 1));
memcpy(u, data->users, data->max_users);
hub_free(data->users);
data->users = u;
data->max_users = sid;
data->max_users = sid + 1;
u = NULL;
}

View File

@@ -21,7 +21,7 @@
#include "adc/adcconst.h"
#include "adc/sid.h"
#include "util/memory.h"
#include "util/ipcalc.h"
#include "network/ipcalc.h"
#include "plugin_api/handle.h"
#include "util/misc.h"

View File

@@ -22,7 +22,7 @@
#include "adc/sid.h"
#include "util/cbuffer.h"
#include "util/memory.h"
#include "util/ipcalc.h"
#include "network/ipcalc.h"
#include "plugin_api/handle.h"
#include "plugin_api/command_api.h"

View File

@@ -99,8 +99,13 @@
#endif
#ifdef SSL_SUPPORT
#ifdef SSL_USE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif /* SSL_USE_OPENSSL */
#ifdef SSL_USE_GNUTLS
#include <gnutls/gnutls.h>
#endif /* SSL_USE_GNUTLS */
#endif
#include "version.h"

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2011, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,9 +23,50 @@
#define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768
#define TIGERSIZE 24
#define MAX_RECV_BUFFER 65536
// #define ADCC_DEBUG
// #define ADC_CLIENT_DEBUG_PROTO
enum ADC_client_state
{
ps_none, /* Not connected */
ps_conn, /* Connecting... */
ps_conn_ssl, /* SSL handshake */
ps_protocol, /* Have sent HSUP */
ps_identify, /* Have sent BINF */
ps_verify, /* Have sent HPAS */
ps_normal, /* Are fully logged in */
};
enum ADC_client_flags
{
cflag_none = 0,
cflag_ssl = 1,
cflag_choke = 2,
cflag_pipe = 4,
};
struct ADC_client
{
sid_t sid;
enum ADC_client_state state;
struct adc_message* info;
struct ioq_recv* recv_queue;
struct ioq_send* send_queue;
adc_client_cb callback;
size_t s_offset;
size_t r_offset;
size_t timeout;
struct net_connection* con;
struct net_timer* timer;
struct sockaddr_in addr;
char* hub_address;
char* nick;
char* desc;
int flags;
void* ptr;
};
static ssize_t ADC_client_recv(struct ADC_client* client);
static void ADC_client_send_info(struct ADC_client* client);
@@ -36,7 +77,8 @@ static void ADC_client_on_connected_ssl(struct ADC_client* client);
static void ADC_client_on_disconnected(struct ADC_client* client);
static void ADC_client_on_login(struct ADC_client* client);
static int ADC_client_parse_address(struct ADC_client* client, const char* arg);
static void ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length);
static int ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length);
static int ADC_client_send_queue(struct ADC_client* client);
static void ADC_client_debug(struct ADC_client* client, const char* format, ...)
{
@@ -146,7 +188,7 @@ static void event_callback(struct net_connection* con, int events, void *arg)
if (events & NET_EVENT_WRITE)
{
/* FIXME: Call send again */
ADC_client_send_queue(client);
}
}
}
@@ -184,7 +226,7 @@ static void event_callback(struct net_connection* con, int events, void *arg)
} while (0)
static void ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length)
static int ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length)
{
struct ADC_chat_message chat;
struct ADC_client_callback_data data;
@@ -199,13 +241,13 @@ static void ADC_client_on_recv_line(struct ADC_client* client, const char* line,
if (!msg)
{
ADC_client_debug(client, "WARNING: Message cannot be decoded: \"%s\"", line);
return;
return -1;
}
if (length < 4)
{
ADC_client_debug(client, "Unexpected response from hub: '%s'", line);
return;
return -1;
}
switch (msg->cmd)
@@ -325,68 +367,126 @@ static void ADC_client_on_recv_line(struct ADC_client* client, const char* line,
}
adc_msg_free(msg);
return 0;
}
static ssize_t ADC_client_recv(struct ADC_client* client)
{
static char buf[BIG_BUFSIZE];
struct ioq_recv* q = client->recv_queue;
size_t buf_size = ioq_recv_get(q, buf, BIG_BUFSIZE);
ssize_t size;
ADC_TRACE;
ssize_t size = net_con_recv(client->con, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset);
if (size <= 0)
return size;
client->r_offset += size;
client->recvbuf[client->r_offset] = 0;
if (client->flags & cflag_choke)
buf_size = 0;
size = net_con_recv(client->con, buf + buf_size, BIG_BUFSIZE - buf_size);
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
size_t remaining = client->r_offset;
if (size > 0)
buf_size += size;
while ((pos = memchr(start, '\n', remaining)))
if (size < 0)
return -1;
else if (size == 0)
return 0;
else
{
pos[0] = 0;
char* lastPos = 0;
char* start = buf;
char* pos = 0;
size_t remaining = buf_size;
ADC_client_on_recv_line(client, start, pos - start);
while ((pos = memchr(start, '\n', remaining)))
{
lastPos = pos+1;
pos[0] = '\0';
pos++;
remaining -= (pos - start);
start = pos;
lastPos = pos;
#ifdef DEBUG_SENDQ
LOG_DUMP("PROC: \"%s\" (%d)\n", start, (int) (pos - start));
#endif
if (client->flags & cflag_choke)
client->flags &= ~cflag_choke;
else
{
if (((pos - start) > 0) && MAX_RECV_BUFFER > (pos - start))
{
if (ADC_client_on_recv_line(client, start, pos - start) == -1)
return -1;
}
}
pos[0] = '\n'; /* FIXME: not needed */
pos ++;
remaining -= (pos - start);
start = pos;
}
if (lastPos || remaining)
{
if (remaining < (size_t) MAX_RECV_BUFFER)
{
ioq_recv_set(q, lastPos ? lastPos : buf, remaining);
}
else
{
ioq_recv_set(q, 0, 0);
client->flags |= cflag_choke;
LOG_WARN("Received message past MAX_RECV_BUFFER (%d), dropping message.", MAX_RECV_BUFFER);
}
}
else
{
ioq_recv_set(q, 0, 0);
}
}
return 0;
}
static int ADC_client_send_queue(struct ADC_client* client)
{
int ret = 0;
while (ioq_send_get_bytes(client->send_queue))
{
ret = ioq_send_send(client->send_queue, client->con);
if (ret <= 0)
break;
}
if (lastPos)
if (ret < 0)
return quit_socket_error;
if (ioq_send_get_bytes(client->send_queue))
{
memmove(client->recvbuf, lastPos, remaining);
client->r_offset = remaining;
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
}
else
{
net_con_update(client->con, NET_EVENT_READ);
}
return 0;
}
void ADC_client_send(struct ADC_client* client, char* msg)
void ADC_client_send(struct ADC_client* client, struct adc_message* msg)
{
ADC_TRACE;
int ret = net_con_send(client->con, msg, strlen(msg));
#ifdef ADC_CLIENT_DEBUG_PROTO
char* dump = strdup(msg);
dump[strlen(msg) - 1] = 0;
ADC_client_debug(client, "- SEND: '%s'", dump);
free(dump);
#endif
uhub_assert(client->con != NULL);
uhub_assert(msg->cache && *msg->cache);
if (ret != strlen(msg))
if (ioq_send_is_empty(client->send_queue) && !(client->flags & cflag_pipe))
{
if (ret == -1)
{
if (net_error() != EWOULDBLOCK)
ADC_client_on_disconnected(client);
}
else
{
/* FIXME: Not all data sent! */
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
}
/* Perform oportunistic write */
ioq_send_add(client->send_queue, msg);
ADC_client_send_queue(client);
}
else
{
ioq_send_add(client->send_queue, msg);
if (!(client->flags & cflag_pipe))
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
}
}
@@ -405,43 +505,38 @@ void ADC_client_send_info(struct ADC_client* client)
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT, PRODUCT "/" VERSION);
adc_cid_pid(client);
ADC_client_send(client, client->info->cache);
ADC_client_send(client, client->info);
}
int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description)
struct ADC_client* ADC_client_create(const char* nickname, const char* description, void* ptr)
{
ADC_TRACE;
memset(client, 0, 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 -1;
if (sd == -1) return NULL;
client->con = net_con_create();
#if 0
/* FIXME */
client->timer = 0; /* FIXME: hub_malloc(sizeof(struct net_timer)); */
#endif
net_con_initialize(client->con, sd, event_callback, client, 0);
#if 0
/* FIXME */
net_timer_initialize(client->timer, timer_callback, client);
#endif
ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname);
client->desc = hub_strdup(description);
return 0;
client->send_queue = ioq_send_create();
client->recv_queue = ioq_recv_create();
client->ptr = ptr;
return client;
}
void ADC_client_destroy(struct ADC_client* client)
{
ADC_TRACE;
ADC_client_disconnect(client);
#if 0
/* FIXME */
net_timer_shutdown(client->timer);
#endif
ioq_send_destroy(client->send_queue);
ioq_recv_destroy(client->recv_queue);
hub_free(client->timer);
adc_msg_free(client->info);
hub_free(client->nick);
@@ -482,18 +577,20 @@ static void ADC_client_on_connected(struct ADC_client* client)
{
ADC_TRACE;
#ifdef SSL_SUPPORT
if (client->ssl_enabled)
if (client->flags & cflag_ssl)
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
client->callback(client, ADC_CLIENT_SSL_HANDSHAKE, 0);
ADC_client_set_state(client, ps_conn_ssl);
net_con_ssl_handshake(client->con, net_con_ssl_mode_client, NULL);
}
else
#endif
{
net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_CONNECTED, 0);
ADC_client_send(client, ADC_HANDSHAKE);
ADC_client_send(client, adc_msg_create(ADC_HANDSHAKE));
ADC_client_set_state(client, ps_protocol);
}
}
@@ -502,9 +599,10 @@ static void ADC_client_on_connected(struct ADC_client* client)
static void ADC_client_on_connected_ssl(struct ADC_client* client)
{
ADC_TRACE;
net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_SSL_OK, 0);
client->callback(client, ADC_CLIENT_CONNECTED, 0);
ADC_client_send(client, ADC_HANDSHAKE);
net_con_update(client->con, NET_EVENT_READ);
ADC_client_send(client, adc_msg_create(ADC_HANDSHAKE));
ADC_client_set_state(client, ps_protocol);
}
#endif
@@ -553,10 +651,12 @@ static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
/* Check for ADC or ADCS */
if (!strncmp(arg, "adc://", 6))
client->ssl_enabled = 0;
{
client->flags &= ~cflag_ssl;
}
else if (!strncmp(arg, "adcs://", 7))
{
client->ssl_enabled = 1;
client->flags |= cflag_ssl;
ssl = 1;
}
else
@@ -594,3 +694,23 @@ void ADC_client_set_callback(struct ADC_client* client, adc_client_cb cb)
ADC_TRACE;
client->callback = cb;
}
sid_t ADC_client_get_sid(const struct ADC_client* client)
{
return client->sid;
}
const char* ADC_client_get_nick(const struct ADC_client* client)
{
return client->nick;
}
const char* ADC_client_get_description(const struct ADC_client* client)
{
return client->desc;
}
void* ADC_client_get_ptr(const struct ADC_client* client)
{
return client->ptr;
}

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2011, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,17 +24,6 @@
#define ADC_BUFSIZE 16384
enum ADC_client_state
{
ps_none, /* Not connected */
ps_conn, /* Connecting... */
ps_conn_ssl, /* SSL handshake */
ps_protocol, /* Have sent HSUP */
ps_identify, /* Have sent BINF */
ps_verify, /* Have sent HPAS */
ps_normal, /* Are fully logged in */
};
struct ADC_client;
enum ADC_client_callback_type
@@ -116,38 +105,19 @@ struct ADC_client_callback_data
};
};
sid_t ADC_client_get_sid(const struct ADC_client* client);
const char* ADC_client_get_nick(const struct ADC_client* client);
const char* ADC_client_get_description(const struct ADC_client* client);
void* ADC_client_get_ptr(const struct ADC_client* client);
typedef int (*adc_client_cb)(struct ADC_client*, enum ADC_client_callback_type, struct ADC_client_callback_data* data);
struct ADC_client
{
sid_t sid;
enum ADC_client_state state;
struct adc_message* info;
char recvbuf[ADC_BUFSIZE];
char sendbuf[ADC_BUFSIZE];
adc_client_cb callback;
size_t s_offset;
size_t r_offset;
size_t timeout;
struct net_connection* con;
struct net_timer* timer;
struct sockaddr_in addr;
char* hub_address;
char* nick;
char* desc;
int ssl_enabled;
#ifdef SSL_SUPPORT
const SSL_METHOD* ssl_method;
SSL_CTX* ssl_ctx;
#endif /* SSL_SUPPORT */
};
int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description);
struct ADC_client* ADC_client_create(const char* nickname, const char* description, void* ptr);
void ADC_client_set_callback(struct ADC_client* client, adc_client_cb);
void ADC_client_destroy(struct ADC_client* client);
int ADC_client_connect(struct ADC_client* client, const char* address);
void ADC_client_disconnect(struct ADC_client* client);
void ADC_client_send(struct ADC_client* client, char* msg);
void ADC_client_send(struct ADC_client* client, struct adc_message* msg);
#endif /* HAVE_UHUB_ADC_CLIENT_H */

View File

@@ -1,6 +1,6 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2011, Jan Vidar Krey
* Copyright (C) 2007-2012, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,10 +24,12 @@
#define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768
#define TIGERSIZE 24
#define STATS_INTERVAL 3
#define ADCRUSH "adcrush/0.3"
#define ADC_NICK "[BOT]adcrush"
#define ADC_DESC "crash\\stest\\sdummy"
#define LVL_INFO 1
#define LVL_DEBUG 2
#define LVL_VERBOSE 3
@@ -38,6 +40,32 @@ static int cfg_level = 1; /* activity level (0..3) */
static int cfg_chat = 0; /* chat mode, allow sending chat messages */
static int cfg_quiet = 0; /* quiet mode (no output) */
static int cfg_clients = ADC_CLIENTS_DEFAULT; /* number of clients */
static int cfg_netstats_interval = STATS_INTERVAL;
static int running = 1;
static int logged_in = 0;
static int blank = 0;
static struct net_statistics* stats_intermediate;
static struct net_statistics* stats_total;
static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data);
static void timer_callback(struct timeout_evt* t);
static void do_blank(int n)
{
n++;
while (n > 0)
{
fprintf(stdout, " ");
n--;
}
}
struct AdcFuzzUser
{
struct ADC_client* client;
struct timeout_evt* timer;
int logged_in;
};
#define MAX_CHAT_MSGS 35
const char* chat_messages[MAX_CHAT_MSGS] = {
@@ -103,10 +131,14 @@ static void bot_output(struct ADC_client* client, int level, const char* format,
va_end(args);
if (cfg_debug >= level)
fprintf(stdout, "* [%p] %s\n", client, logmsg);
{
int num = fprintf(stdout, "* [%p] %s", client, logmsg);
do_blank(blank - num);
fprintf(stdout, "\n");
}
}
#if 0
static size_t get_wait_rand(size_t max)
{
static size_t next = 0;
@@ -115,120 +147,144 @@ static size_t get_wait_rand(size_t max)
return ((size_t )(next / 65536) % max);
}
static size_t get_next_timeout_evt()
{
switch (cfg_level)
{
case 0: return get_wait_rand(120);
case 1: return get_wait_rand(60);
case 2: return get_wait_rand(15);
case 3: return get_wait_rand(5);
}
}
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token);
static void perf_chat(struct ADC_client* client, int priv)
{
char buf[1024] = { 0, };
size_t r = get_wait_rand(MAX_CHAT_MSGS-1);
char* msg = adc_msg_escape(chat_messages[r]);
struct adc_message* cmd = NULL;
if (priv)
{
strcat(buf, "EMSG ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " ");
strcat(buf, sid_to_string(client->sid));
}
cmd = adc_msg_construct_source_dest(ADC_CMD_DMSG, ADC_client_get_sid(client), ADC_client_get_sid(client), strlen(msg));
else
{
strcat(buf, "BMSG ");
strcat(buf, sid_to_string(client->sid));
}
strcat(buf, " ");
strcat(buf, msg);
cmd = adc_msg_construct_source(ADC_CMD_BMSG, ADC_client_get_sid(client), strlen(msg));
hub_free(msg);
strcat(buf, "\n");
ADC_client_send(client, buf);
ADC_client_send(client, cmd);
}
static void perf_search(struct ADC_client* client)
{
char buf[1024] = { 0, };
size_t r = get_wait_rand(MAX_SEARCH_MSGS-1);
size_t pst = get_wait_rand(100);
struct adc_message* cmd = NULL;
if (pst > 80)
{
strcat(buf, "FSCH ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " +TCP4 ");
cmd = adc_msg_construct_source(ADC_CMD_FSCH, ADC_client_get_sid(client), strlen(search_messages[r]) + 6);
adc_msg_add_argument(cmd, "+TCP4");
}
else
{
strcat(buf, "BSCH ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " ");
cmd = adc_msg_construct_source(ADC_CMD_BSCH, ADC_client_get_sid(client), strlen(search_messages[r]) + 6);
adc_msg_add_argument(cmd, "+TCP4");
}
strcat(buf, search_messages[r]);
strcat(buf, "\n");
ADC_client_send(client, buf);
ADC_client_send(client, cmd);
}
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token)
{
char buf[1024] = { 0, };
strcat(buf, "DRES ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " ");
strcat(buf, sid_to_string(target));
strcat(buf, " FN" "test/");
strcat(buf, what);
strcat(buf, ".dat");
strcat(buf, " SL" "0");
strcat(buf, " SI" "908987128912");
strcat(buf, " TR" "5T6YJYKO3WECS52BKWVSOP5VUG4IKNSZBZ5YHBA");
strcat(buf, " TO");
strcat(buf, token);
strcat(buf, "\n");
ADC_client_send(client, buf);
char tmp[256];
struct adc_message* cmd = adc_msg_construct_source_dest(ADC_CMD_DRES, ADC_client_get_sid(client), target, strlen(what) + strlen(token) + 64);
snprintf(tmp, sizeof(tmp), "FNtest/%s.dat", what);
adc_msg_add_argument(cmd, tmp);
adc_msg_add_argument(cmd, "SL0");
adc_msg_add_argument(cmd, "SI1209818412");
adc_msg_add_argument(cmd, "TR5T6YJYKO3WECS52BKWVSOP5VUG4IKNSZBZ5YHBA");
snprintf(tmp, sizeof(tmp), "TO%s", token);
adc_msg_add_argument(cmd, tmp);
ADC_client_send(client, cmd);
}
static void perf_ctm(struct ADC_client* client)
{
char buf[1024] = { 0, };
strcat(buf, "DCTM ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " ");
strcat(buf, "ADC/1.0");
strcat(buf, " TOKEN111");
strcat(buf, sid_to_string(client->sid));
strcat(buf, "\n");
ADC_client_send(client, buf);
struct adc_message* cmd = adc_msg_construct_source_dest(ADC_CMD_DCTM, ADC_client_get_sid(client), ADC_client_get_sid(client), 32);
adc_msg_add_argument(cmd, "ADC/1.0");
adc_msg_add_argument(cmd, "TOKEN123456");
adc_msg_add_argument(cmd, sid_to_string(ADC_client_get_sid(client)));
ADC_client_send(client, cmd);
}
static void perf_update(struct ADC_client* client)
{
char buf[1024] = { 0, };
char buf[16] = { 0, };
int n = (int) get_wait_rand(10)+1;
struct adc_message* cmd = adc_msg_construct_source(ADC_CMD_BINF, ADC_client_get_sid(client), 32);
snprintf(buf, sizeof(buf), "HN%d", n);
adc_msg_add_argument(cmd, buf);
ADC_client_send(client, cmd);
}
strcat(buf, "BINF ");
strcat(buf, sid_to_string(client->sid));
strcat(buf, " HN");
strcat(buf, uhub_itoa(n));
static void client_disconnect(struct AdcFuzzUser* c)
{
ADC_client_destroy(c->client);
hub_free(c->client);
c->client = 0;
strcat(buf, "\n");
ADC_client_send(client, buf);
timeout_queue_remove(net_backend_get_timeout_queue(), c->timer);
hub_free(c->timer);
c->timer = 0;
c->logged_in = 0;
}
static void client_connect(struct AdcFuzzUser* c, const char* nick, const char* description)
{
size_t timeout = get_next_timeout_evt();
struct ADC_client* client = ADC_client_create(nick, description, c);
c->client = client;
c->timer = (struct timeout_evt*) hub_malloc(sizeof(struct timeout_evt));
timeout_evt_initialize(c->timer, timer_callback, c);
timeout_queue_insert(net_backend_get_timeout_queue(), c->timer, timeout);
bot_output(client, LVL_VERBOSE, "Initial timeout: %d seconds", timeout);
c->logged_in = 0;
ADC_client_set_callback(client, handle);
ADC_client_connect(client, cfg_uri);
}
static void perf_normal_action(struct ADC_client* client)
{
struct AdcFuzzUser* user = (struct AdcFuzzUser*) ADC_client_get_ptr(client);
size_t r = get_wait_rand(5);
size_t p = get_wait_rand(100);
switch (r)
{
case 0:
if (p > (90 - (10 * cfg_level)))
// if (p > (90 - (10 * cfg_level)))
{
struct ADC_client* c;
char* nick = hub_strdup(ADC_client_get_nick(client));
char* desc = hub_strdup(ADC_client_get_description(client));
bot_output(client, LVL_VERBOSE, "timeout -> disconnect");
ADC_client_disconnect(client);
client_disconnect(user);
client_connect(user, nick, desc);
hub_free(nick);
hub_free(desc);
}
break;
@@ -236,37 +292,43 @@ static void perf_normal_action(struct ADC_client* client)
if (cfg_chat)
{
bot_output(client, LVL_VERBOSE, "timeout -> chat");
perf_chat(client, 0);
if (user->logged_in)
perf_chat(client, 0);
}
break;
case 2:
bot_output(client, LVL_VERBOSE, "timeout -> search");
perf_search(client);
if (user->logged_in)
perf_search(client);
break;
case 3:
bot_output(client, LVL_VERBOSE, "timeout -> update");
perf_update(client);
if (user->logged_in)
perf_update(client);
break;
case 4:
bot_output(client, LVL_VERBOSE, "timeout -> privmsg");
perf_chat(client, 1);
if (user->logged_in)
perf_chat(client, 1);
break;
case 5:
bot_output(client, LVL_VERBOSE, "timeout -> ctm/rcm");
perf_ctm(client);
if (user->logged_in)
perf_ctm(client);
break;
}
}
#endif
static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data)
{
struct AdcFuzzUser* user = (struct AdcFuzzUser*) ADC_client_get_ptr(client);
switch (type)
{
case ADC_CLIENT_CONNECTING:
@@ -274,7 +336,7 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
break;
case ADC_CLIENT_CONNECTED:
bot_output(client, LVL_DEBUG, "*** Connected.");
// bot_output(client, LVL_DEBUG, "*** Connected.");
break;
case ADC_CLIENT_DISCONNECTED:
@@ -282,38 +344,40 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
break;
case ADC_CLIENT_LOGGING_IN:
bot_output(client, LVL_DEBUG, "*** Logging in...");
// bot_output(client, LVL_DEBUG, "*** Logging in...");
break;
case ADC_CLIENT_PASSWORD_REQ:
bot_output(client, LVL_DEBUG, "*** Requesting password.");
//bot_output(client, LVL_DEBUG, "*** Requesting password.");
break;
case ADC_CLIENT_LOGGED_IN:
bot_output(client, LVL_DEBUG, "*** Logged in.");
user->logged_in = 1;
break;
case ADC_CLIENT_LOGIN_ERROR:
bot_output(client, LVL_DEBUG, "*** Login error");
break;
case ADC_CLIENT_SSL_HANDSHAKE:
case ADC_CLIENT_SSL_OK:
break;
case ADC_CLIENT_MESSAGE:
bot_output(client, LVL_DEBUG, " <%s> %s", sid_to_string(data->chat->from_sid), data->chat->message);
// bot_output(client, LVL_DEBUG, " <%s> %s", sid_to_string(data->chat->from_sid), data->chat->message);
break;
case ADC_CLIENT_USER_JOIN:
bot_output(client, LVL_VERBOSE, " JOIN: %s", data->user->name);
break;
case ADC_CLIENT_USER_QUIT:
bot_output(client, LVL_VERBOSE, " QUIT");
break;
case ADC_CLIENT_SEARCH_REQ:
break;
case ADC_CLIENT_HUB_INFO:
bot_output(client, LVL_DEBUG, " Hub: \"%s\" [%s]\n"
" \"%s\"\n", data->hubinfo->name, data->hubinfo->version, data->hubinfo->description);
break;
default:
@@ -324,40 +388,78 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
return 1;
}
static void timer_callback(struct timeout_evt* t)
{
size_t timeout = get_next_timeout_evt();
struct AdcFuzzUser* client = (struct AdcFuzzUser*) t->ptr;
if (client->logged_in)
{
perf_normal_action(client->client);
bot_output(client->client, LVL_VERBOSE, "Next timeout: %d seconds", (int) timeout);
}
timeout_queue_reschedule(net_backend_get_timeout_queue(), client->timer, timeout);
}
static struct AdcFuzzUser client[ADC_MAX_CLIENTS];
void p_status()
{
static char rxbuf[64] = { "0 B" };
static char txbuf[64] = { "0 B" };
int logged_in = 0;
size_t n;
static size_t rx = 0, tx = 0;
for (n = 0; n < cfg_clients; n++)
{
if (client[n].logged_in)
logged_in++;
}
if (difftime(time(NULL), stats_intermediate->timestamp) >= cfg_netstats_interval)
{
net_stats_get(&stats_intermediate, &stats_total);
rx = stats_intermediate->rx / cfg_netstats_interval;
tx = stats_intermediate->tx / cfg_netstats_interval;
net_stats_reset();
format_size(rx, rxbuf, sizeof(rxbuf));
format_size(tx, txbuf, sizeof(txbuf));
}
n = blank;
blank = printf("Connected bots: %d/%d, network: rx=%s/s, tx=%s/s", logged_in, cfg_clients, rxbuf, txbuf);
if (n > blank)
do_blank(n-blank);
printf("\r");
}
void runloop(size_t clients)
{
size_t n = 0;
struct ADC_client* client[ADC_MAX_CLIENTS];
blank = 0;
for (n = 0; n < clients; n++)
{
struct ADC_client* c = malloc(sizeof(struct ADC_client));
client[n] = c;
char nick[20];
snprintf(nick, 20, "adcrush_%d", (int) n);
ADC_client_create(c, nick, "stresstester");
ADC_client_set_callback(c, handle);
ADC_client_connect(c, cfg_uri);
client_connect(&client[n], nick, "stresstester");
}
while (net_backend_process())
while (running && net_backend_process())
{
p_status();
}
for (n = 0; n < clients; n++)
{
ADC_client_destroy(client[n]);
free(client[n]);
client[n] = 0;
struct AdcFuzzUser* c = &client[n];
client_disconnect(c);
}
}
static void print_version()
{
printf(ADCRUSH "\n");
printf("Copyright (C) 2008-2009, Jan Vidar Krey\n");
printf("Copyright (C) 2008-2012, Jan Vidar Krey\n");
printf("\n");
}
@@ -374,6 +476,7 @@ static void print_usage(const char* program)
printf(" -c Allow broadcasting chat messages.\n");
printf(" -d Enable debug output.\n");
printf(" -q Quiet mode (no output).\n");
printf(" -i <num> Average network statistics for given interval (default: 3)\n");
printf("\n");
exit(0);
@@ -407,6 +510,10 @@ int parse_arguments(int argc, char** argv)
{
cfg_level = MIN(MAX(uhub_atoi(argv[opt]), 0), 3);
}
else if (!strcmp(argv[opt], "-i") && (++opt) < argc)
{
cfg_netstats_interval = MAX(uhub_atoi(argv[opt]), 1);
}
else if (!strcmp(argv[opt], "-n") && (++opt) < argc)
{
cfg_clients = MIN(MAX(uhub_atoi(argv[opt]), 1), ADC_MAX_CLIENTS);
@@ -428,13 +535,15 @@ void parse_command_line(int argc, char** argv)
int main(int argc, char** argv)
{
parse_command_line(argc, argv);
net_initialize();
net_stats_get(&stats_intermediate, &stats_total);
hub_log_initialize(NULL, 0);
hub_set_log_verbosity(1000);
setvbuf(stdout, NULL, _IONBF, 0);
runloop(cfg_clients);
net_destroy();

View File

@@ -163,18 +163,18 @@ int main(int argc, char** argv)
return 1;
}
struct ADC_client client;
struct ADC_client* client;
net_initialize();
memset(g_usermap, 0, sizeof(g_usermap));
ADC_client_create(&client, "uhub-admin", "stresstester");
ADC_client_set_callback(&client, handle);
ADC_client_connect(&client, argv[1]);
client = ADC_client_create("uhub-admin", "stresstester", NULL);
ADC_client_set_callback(client, handle);
ADC_client_connect(client, argv[1]);
while (running && net_backend_process()) { }
ADC_client_destroy(&client);
ADC_client_destroy(client);
net_destroy();
return 0;
}

View File

@@ -41,7 +41,7 @@
#define TIMEOUT_CONNECTED 15
#define TIMEOUT_HANDSHAKE 30
#define TIMEOUT_SENDQ 120
#define TIMEOUT_STATS 60
#define TIMEOUT_STATS 10
#define MAX_CID_LEN 39
#define MAX_NICK_LEN 64
@@ -63,7 +63,6 @@ extern "C" {
#include "util/credentials.h"
#include "util/floodctl.h"
#include "util/getopt.h"
#include "util/ipcalc.h"
#include "util/list.h"
#include "util/log.h"
#include "util/memory.h"
@@ -75,6 +74,7 @@ extern "C" {
#include "network/network.h"
#include "network/connection.h"
#include "network/ipcalc.h"
#include "network/timeout.h"
#include "core/auth.h"

View File

@@ -36,6 +36,7 @@ extern struct cbuffer* cbuf_create(size_t capacity)
buf->size = 0;
buf->flags = 0;
buf->buf = hub_malloc(capacity + 1);
buf->buf[0] = '\0';
return buf;
}

View File

@@ -305,6 +305,27 @@ int is_number(const char* value, int* num)
}
const char* format_size(size_t bytes, char* buf, size_t bufsize)
{
static const char* quant[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" };
size_t b = bytes;
size_t factor = 0;
size_t divisor = 1;
while (b > 1024)
{
factor++;
b = (b >> 10);
divisor = (divisor << 10);
}
uhub_assert(factor < (sizeof(quant) / sizeof(const char*)));
if (factor >= 2)
snprintf(buf, bufsize, "%.1f %s", (double) bytes / (double) divisor, quant[factor]);
else
snprintf(buf, bufsize, PRINTF_SIZE_T " %s", bytes / divisor, quant[factor]);
return buf;
}
const char* uhub_itoa(int val)
{
static char buf[22];

View File

@@ -42,6 +42,19 @@ extern char* strip_off_quotes(char* line);
*/
extern int is_number(const char* str, int* num);
/**
* Convert the 'bytes' number into a formatted byte size string.
* E.g. "129012" becomes "125.99 KB".
* Note, if the output buffer is not large enough then the output
* will be truncated. The buffer will always be \0 terminated.
*
* @param bytes the number that should be formatted.
* @param[out] buf the buffer the string should be formatted into
* @param bufsize the size of 'buf'
* @return A pointer to buf.
*/
extern const char* format_size(size_t bytes, char* buf, size_t bufsize);
extern int file_read_lines(const char* file, void* data, file_line_handler_t handler);
/**

View File

@@ -23,14 +23,12 @@
#define VERSION "@UHUB_VERSION_MAJOR@.@UHUB_VERSION_MINOR@.@UHUB_VERSION_PATCH@"
#endif
#define GIT_REVISION "@UHUB_REVISION@"
#define GIT_VERSION "@UHUB_GIT_VERSION@"
#ifndef PRODUCT
#define PRODUCT "uhub"
#endif
#define REVISION GIT_REVISION
#define PRODUCT_STRING PRODUCT "/" GIT_VERSION
#ifndef COPYRIGHT