Compare commits

...

28 Commits

Author SHA1 Message Date
Jan Vidar Krey
92c448b855 Dont use SSL by default. 2010-01-23 01:09:00 +01:00
Jan Vidar Krey
304ecda16a Enable the statistics timer again, so that !stats provide up to date network statistics. 2010-01-23 00:43:38 +01:00
Jan Vidar Krey
c670d13369 Make sure we shutdown SSL connections when an error occurs. 2010-01-23 00:20:48 +01:00
Jan Vidar Krey
b2e7a2848f Optimize epoll to never modify the epoll mask unless it actually changed. 2010-01-23 00:03:45 +01:00
Jan Vidar Krey
84bd2591d6 SSL fixes, seems to work with stunnel4 as a client but not linuxdcpp using SSL directly. 2010-01-22 23:43:23 +01:00
Jan Vidar Krey
4aa65733d0 Poll as long as possible until next timeout the earliest. 2010-01-22 23:18:59 +01:00
Jan Vidar Krey
230ca28b46 Some unfinished SSL work. 2010-01-22 18:52:38 +01:00
Jan Vidar Krey
5f353ebe28 Added script to create SSL certificate. 2010-01-22 18:22:39 +01:00
Jan Vidar Krey
68a26e1160 Added proper POSIX signal handler. 2010-01-22 16:57:30 +01:00
Jan Vidar Krey
4711d26c11 Fix broken net_address_to_string(). 2010-01-22 16:09:19 +01:00
Jan Vidar Krey
1bb3bd90c1 Use non-default port to ensure autotests work even though a hub is running on the default port. 2010-01-22 16:05:48 +01:00
Jan Vidar Krey
5e253e8442 Fix compile error. 2010-01-22 16:04:36 +01:00
Jan Vidar Krey
26a2a384b6 Bump to version 0.3.0 2010-01-22 16:01:54 +01:00
Jan Vidar Krey
8b7f09c7f4 Fixed two cases of bad connection close. 2010-01-21 23:54:38 +01:00
Jan Vidar Krey
b29da11f3b Make sure we call the timeout code. 2010-01-21 23:52:04 +01:00
Jan Vidar Krey
78ad9b8572 Fixed bad logic inside the timer scheduling. 2010-01-21 23:13:52 +01:00
Jan Vidar Krey
b04a20c66e fixed off by one bug in due to message escape. 2010-01-21 22:20:26 +01:00
Jan Vidar Krey
21a5981905 Make sure start_listening_socket does everything, this will lead the way to multiple listen ports. 2010-01-21 17:31:55 +01:00
Jan Vidar Krey
c47ea14047 Code cleanup for starting the listening socket. 2010-01-21 01:54:41 +01:00
Jan Vidar Krey
9f5aaf0148 Added a safe connection cleanup procedure for when a connection goes
down while it may be attempted to be used.
2010-01-21 01:12:57 +01:00
Jan Vidar Krey
f645811f37 Merge branch 'master' of github.com:janvidar/uhub 2010-01-20 18:42:45 +01:00
Jan Vidar Krey
2f09fcea84 Added select() backend which can be used as a fallback if epoll is not available. 2010-01-20 18:39:55 +01:00
root
5e679e2d4f - add doc/init.d.RedHat/etc/logrotator.d/uhub file 2010-01-20 11:18:16 +03:00
root
efeb36c492 - update uhub.conf example after add !rules
- add example rules.txt
- fix compile warning in  src/util/timeout.c
- add example config file for rotate log file in RHEL\CentOS
2010-01-20 11:12:43 +03:00
Jan Vidar Krey
7e60919596 sorted the commands shown in help. 2010-01-20 00:24:57 +01:00
Jan Vidar Krey
e7cb4cd277 remove extra space before !broadcast messages 2010-01-20 00:12:39 +01:00
Jan Vidar Krey
e45511827f Added the +rules command.
Also added the +motd command to see the message of the day, which is sent while connecting.
2010-01-19 23:30:26 +01:00
Jan Vidar Krey
80c6ad9d76 Added mute/unmute functionality. 2010-01-19 23:07:55 +01:00
38 changed files with 929 additions and 849 deletions

View File

@@ -9,7 +9,6 @@ MV := mv
RANLIB := ranlib RANLIB := ranlib
CFLAGS += -pipe -Wall CFLAGS += -pipe -Wall
USE_SSL ?= NO USE_SSL ?= NO
USE_LIBEVENT ?= NO
USE_BIGENDIAN ?= AUTO USE_BIGENDIAN ?= AUTO
BITS ?= AUTO BITS ?= AUTO
SILENT ?= YES SILENT ?= YES
@@ -63,9 +62,6 @@ else
MSG_CLEAN="Clean as a whistle" MSG_CLEAN="Clean as a whistle"
endif endif
# CFLAGS += -I/source/libevent
# LDFLAGS += -L/source/libevent
ifeq ($(RELEASE),YES) ifeq ($(RELEASE),YES)
CFLAGS += -O3 -DNDEBUG CFLAGS += -O3 -DNDEBUG
GIT_REVISION ?= NO GIT_REVISION ?= NO
@@ -116,15 +112,6 @@ CFLAGS += -DSSL_SUPPORT
LDLIBS += -lssl LDLIBS += -lssl
endif endif
ifeq ($(USE_LIBEVENT),YES)
CFLAGS += -DUSE_LIBEVENT
LDLIBS += -levent
ifneq ($(LIBEVENT_PATH),)
CFLAGS += -I$(LIBEVENT_PATH)
LDFLAGS += -L$(LIBEVENT_PATH)
endif
endif
ifeq ($(GIT_REVISION),YES) ifeq ($(GIT_REVISION),YES)
CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\" CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\"
endif endif
@@ -144,10 +131,12 @@ libuhub_SOURCES := \
src/core/route.c \ src/core/route.c \
src/core/user.c \ src/core/user.c \
src/core/usermanager.c \ src/core/usermanager.c \
src/network/backend.c \
src/network/connection.c \ src/network/connection.c \
src/network/epoll.c \ src/network/epoll.c \
src/network/libevent.c \
src/network/network.c \ src/network/network.c \
src/network/select.c \
src/network/timer.c \
src/util/ipcalc.c \ src/util/ipcalc.c \
src/util/list.c \ src/util/list.c \
src/util/log.c \ src/util/log.c \

View File

@@ -23,6 +23,7 @@ EXO_TEST(hub_net_startup, {
EXO_TEST(hub_config_initialize, { EXO_TEST(hub_config_initialize, {
config_defaults(&g_config); config_defaults(&g_config);
g_config.server_port = 15111;
return 1; return 1;
}); });

View File

@@ -0,0 +1,13 @@
# Log rotate for Uhub
# see man logrotate
#
#
/var/log/uhub.log {
compress
size 10M
rotate 10
missingok
notifempty
}

5
doc/rules.txt Normal file
View File

@@ -0,0 +1,5 @@
1. rule #1
2. rule #2
3. rule #3
......
34. Rule #34

View File

@@ -39,6 +39,11 @@ file_acl=/etc/uhub/users.conf
# Normally this message is sent to clients when connecting. # Normally this message is sent to clients when connecting.
file_motd=/etc/uhub/motd.txt file_motd=/etc/uhub/motd.txt
# This file can contain a rules of the hub.
# Normally this message is sent to clients when write in chat !rules
file_rules=/etc/uhub/rules.txt
# Slots\share\hubs limits # Slots\share\hubs limits
limit_max_hubs_user = 0 limit_max_hubs_user = 0
limit_max_hubs_reg = 0 limit_max_hubs_reg = 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-2010, 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
@@ -276,6 +276,28 @@ static int command_unban(struct hub_info* hub, struct hub_user* user, struct hub
return command_status(hub, user, cmd, "Not implemented"); return command_status(hub, user, cmd, "Not implemented");
} }
static int command_mute(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* nick = list_get_first(cmd->args);
if (!nick)
return -1; // FIXME: bad syntax.
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
if (strlen(cmd->prefix) == 4)
{
user_flag_set(target, flag_muted);
}
else
{
user_flag_unset(target, flag_muted);
}
return command_status(hub, user, cmd, nick);
}
static int command_reload(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_reload(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
hub->status = hub_status_restart; hub->status = hub_status_restart;
@@ -377,8 +399,8 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub
static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen((cmd->message + 10)) + 6); struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen((cmd->message + 12)) + 6);
adc_msg_add_argument(command, (cmd->message + 10)); adc_msg_add_argument(command, (cmd->message + 12));
route_to_all(hub, command); route_to_all(hub, command);
adc_msg_free(command); adc_msg_free(command);
return 0; return 0;
@@ -496,6 +518,20 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c
return 0; return 0;
} }
static int command_rules(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
if (!hub_send_rules(hub, user))
return command_status(hub, user, cmd, "no rules defined.");
return 0;
}
static int command_motd(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
if (!hub_send_motd(hub, user))
return command_status(hub, user, cmd, "no motd defined.");
return 0;
}
#ifdef CRASH_DEBUG #ifdef CRASH_DEBUG
static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
@@ -550,24 +586,28 @@ int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* m
} }
static struct commands_handler command_handlers[] = { static struct commands_handler command_handlers[] = {
{ "help", 4, 0, cred_guest, command_help, "Show this help message." },
{ "stats", 5, 0, cred_super, command_stats, "Show hub statistics." },
{ "version", 7, 0, cred_guest, command_version, "Show hub version info." },
{ "history", 7, 0, cred_guest, command_history, "Show the last chat messages." },
{ "uptime", 6, 0, cred_guest, command_uptime, "Display hub uptime info." },
{ "kick", 4, "n", cred_operator, command_kick, "Kick a user" },
{ "ban", 3, "n", cred_operator, command_ban, "Ban a user" }, { "ban", 3, "n", cred_operator, command_ban, "Ban a user" },
{ "unban", 5, "n", cred_operator, command_unban, "Lift ban on a user" },
{ "reload", 6, 0, cred_admin, command_reload, "Reload configuration files." },
{ "shutdown", 8, 0, cred_admin, command_shutdown, "Shutdown hub." },
{ "myip", 4, 0, cred_guest, command_myip, "Show your own IP." },
{ "getip", 5, "n", cred_operator, command_getip, "Show IP address for a user" },
{ "whoip", 5, "a", cred_operator, command_whoip, "Show users matching IP range" },
{ "broadcast", 9, "m", cred_operator, command_broadcast,"Send a message to all users" }, { "broadcast", 9, "m", cred_operator, command_broadcast,"Send a message to all users" },
{ "log", 3, 0, cred_operator, command_log, "Display log" },
#ifdef CRASH_DEBUG #ifdef CRASH_DEBUG
{ "crash", 5, 0, cred_admin, command_crash, "Crash the hub (DEBUG)." }, { "crash", 5, 0, cred_admin, command_crash, "Crash the hub (DEBUG)." },
#endif #endif
{ "getip", 5, "n", cred_operator, command_getip, "Show IP address for a user" },
{ "help", 4, 0, cred_guest, command_help, "Show this help message." },
{ "history", 7, 0, cred_guest, command_history, "Show the last chat messages." },
{ "kick", 4, "n", cred_operator, command_kick, "Kick a user" },
{ "log", 3, 0, cred_operator, command_log, "Display log" },
{ "motd", 4, 0, cred_guest, command_motd, "Show the message of the day" },
{ "mute", 4, "n", cred_operator, command_mute, "Mute user" },
{ "myip", 4, 0, cred_guest, command_myip, "Show your own IP." },
{ "reload", 6, 0, cred_admin, command_reload, "Reload configuration files." },
{ "rules", 5, 0, cred_guest, command_rules, "Show the hub rules" },
{ "shutdown", 8, 0, cred_admin, command_shutdown, "Shutdown hub." },
{ "stats", 5, 0, cred_super, command_stats, "Show hub statistics." },
{ "unban", 5, "n", cred_operator, command_unban, "Lift ban on a user" },
{ "unmute", 6, "n", cred_operator, command_mute, "Unmute user" },
{ "uptime", 6, 0, cred_guest, command_uptime, "Display hub uptime info." },
{ "version", 7, 0, cred_guest, command_version, "Show hub version info." },
{ "whoip", 5, "a", cred_operator, command_whoip, "Show users matching IP range" },
{ 0, 0, 0, cred_none, command_help, "" } { 0, 0, 0, cred_none, command_help, "" }
}; };

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-2010, 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

@@ -116,6 +116,7 @@
#define DEF_HUB_ENABLED 1 #define DEF_HUB_ENABLED 1
#define DEF_FILE_ACL "" #define DEF_FILE_ACL ""
#define DEF_FILE_MOTD "" #define DEF_FILE_MOTD ""
#define DEF_FILE_RULES ""
#define DEF_MAX_USERS 500 #define DEF_MAX_USERS 500
#define DEF_MAX_CHAT_HISTORY 20 #define DEF_MAX_CHAT_HISTORY 20
#define DEF_MAX_LOGOUT_LOG 100 #define DEF_MAX_LOGOUT_LOG 100
@@ -180,6 +181,7 @@ void config_defaults(struct hub_config* config)
DEFAULT_BOOLEAN(hub_enabled, DEF_HUB_ENABLED); DEFAULT_BOOLEAN(hub_enabled, DEF_HUB_ENABLED);
DEFAULT_STRING (file_acl, DEF_FILE_ACL); DEFAULT_STRING (file_acl, DEF_FILE_ACL);
DEFAULT_STRING (file_motd, DEF_FILE_MOTD); DEFAULT_STRING (file_motd, DEF_FILE_MOTD);
DEFAULT_STRING (file_rules, DEF_FILE_RULES);
DEFAULT_INTEGER(server_port, DEF_SERVER_PORT); DEFAULT_INTEGER(server_port, DEF_SERVER_PORT);
DEFAULT_INTEGER(server_listen_backlog, DEF_SERVER_BACKLOG); DEFAULT_INTEGER(server_listen_backlog, DEF_SERVER_BACKLOG);
DEFAULT_INTEGER(max_users, DEF_MAX_USERS); DEFAULT_INTEGER(max_users, DEF_MAX_USERS);
@@ -249,6 +251,7 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
{ {
GET_STR (file_acl); GET_STR (file_acl);
GET_STR (file_motd); GET_STR (file_motd);
GET_STR (file_rules);
GET_STR (server_bind_addr); GET_STR (server_bind_addr);
GET_INT (server_port); GET_INT (server_port);
GET_INT (server_listen_backlog); GET_INT (server_listen_backlog);
@@ -327,6 +330,7 @@ void free_config(struct hub_config* config)
hub_free(config->server_bind_addr); hub_free(config->server_bind_addr);
hub_free(config->file_motd); hub_free(config->file_motd);
hub_free(config->file_acl); hub_free(config->file_acl);
hub_free(config->file_rules);
hub_free(config->hub_name); hub_free(config->hub_name);
hub_free(config->hub_description); hub_free(config->hub_description);
@@ -398,6 +402,7 @@ void dump_config(struct hub_config* config, int ignore_defaults)
{ {
DUMP_STR (file_acl, DEF_FILE_ACL); DUMP_STR (file_acl, DEF_FILE_ACL);
DUMP_STR (file_motd, DEF_FILE_MOTD); DUMP_STR (file_motd, DEF_FILE_MOTD);
DUMP_STR (file_rules, DEF_FILE_RULES);
DUMP_STR (server_bind_addr, DEF_SERVER_BIND_ADDR); DUMP_STR (server_bind_addr, DEF_SERVER_BIND_ADDR);
DUMP_INT (server_port, DEF_SERVER_PORT); DUMP_INT (server_port, DEF_SERVER_PORT);
DUMP_INT (server_listen_backlog, DEF_SERVER_BACKLOG); DUMP_INT (server_listen_backlog, DEF_SERVER_BACKLOG);

View File

@@ -33,6 +33,7 @@ struct hub_config
int chat_is_privileged; /**<<< "Allow chat for operators and above only (default: 0) */ int chat_is_privileged; /**<<< "Allow chat for operators and above only (default: 0) */
char* file_motd; /**<<< "File containing the 'message of the day' (default: '' - no motd)" */ char* file_motd; /**<<< "File containing the 'message of the day' (default: '' - no motd)" */
char* file_acl; /**<<< "File containing user database (default: '' - no known users)" */ char* file_acl; /**<<< "File containing user database (default: '' - no known users)" */
char* file_rules; /**<<< "File containing the rules (default: '' - no rules)" */
char* hub_name; /**<<< "Name of hub (default: 'My uhub hub')" */ char* hub_name; /**<<< "Name of hub (default: 'My uhub hub')" */
char* hub_description; /**<<< "Name of hub (default: 'no description')" */ char* hub_description; /**<<< "Name of hub (default: 'no description')" */
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)" */

View File

@@ -206,7 +206,7 @@ int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc
} }
} }
if (hub->config->chat_is_privileged && !user_is_protected(u) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F')) if (((hub->config->chat_is_privileged && !user_is_protected(u)) || (user_flag_get(u, flag_muted))) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F'))
{ {
relay = 0; relay = 0;
} }
@@ -361,14 +361,27 @@ void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
} }
} }
void hub_send_motd(struct hub_info* hub, struct hub_user* u) int hub_send_motd(struct hub_info* hub, struct hub_user* u)
{ {
if (hub->command_motd) if (hub->command_motd)
{ {
route_to_user(hub, u, hub->command_motd); route_to_user(hub, u, hub->command_motd);
return 1;
} }
return 0;
} }
int hub_send_rules(struct hub_info* hub, struct hub_user* u)
{
if (hub->command_rules)
{
route_to_user(hub, u, hub->command_rules);
return 1;
}
return 0;
}
void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u) void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
{ {
struct adc_message* igpa; struct adc_message* igpa;
@@ -437,14 +450,56 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message
} }
} }
static struct net_connection* start_listening_socket(const char* bind_addr, uint16_t port, int backlog, struct hub_info* hub)
{
struct net_connection* server;
struct sockaddr_storage addr;
socklen_t sockaddr_size;
int sd, ret;
if (ip_convert_address(bind_addr, port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
{
return 0;
}
sd = net_socket_create(addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1)
{
return 0;
}
if ((net_set_reuseaddress(sd, 1) == -1) || (net_set_nonblocking(sd, 1) == -1))
{
net_close(sd);
return 0;
}
ret = net_bind(sd, (struct sockaddr*) &addr, sockaddr_size);
if (ret == -1)
{
LOG_ERROR("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
net_close(sd);
return 0;
}
ret = net_listen(sd, backlog);
if (ret == -1)
{
LOG_ERROR("hub_start_service(): Unable to listen to socket");
net_close(sd);
return 0;
}
server = net_con_create();
net_con_initialize(server, sd, net_on_accept, hub, NET_EVENT_READ);
return server;
}
struct hub_info* hub_start_service(struct hub_config* config) struct hub_info* hub_start_service(struct hub_config* config)
{ {
struct hub_info* hub = 0; struct hub_info* hub = 0;
struct sockaddr_storage addr; int ipv6_supported;
socklen_t sockaddr_size;
int server_tcp, ret, ipv6_supported, af;
char address_buf[INET6_ADDRSTRLEN+1];
hub = hub_malloc_zero(sizeof(struct hub_info)); hub = hub_malloc_zero(sizeof(struct hub_info));
if (!hub) if (!hub)
@@ -454,72 +509,20 @@ struct hub_info* hub_start_service(struct hub_config* config)
} }
hub->tm_started = time(0); hub->tm_started = time(0);
ipv6_supported = net_is_ipv6_supported(); ipv6_supported = net_is_ipv6_supported();
if (ipv6_supported) if (ipv6_supported)
LOG_DEBUG("IPv6 supported."); LOG_DEBUG("IPv6 supported.");
else else
LOG_DEBUG("IPv6 not supported."); LOG_DEBUG("IPv6 not supported.");
if (ip_convert_address(config->server_bind_addr, config->server_port, (struct sockaddr*) &addr, &sockaddr_size) == -1) hub->server = start_listening_socket(config->server_bind_addr, config->server_port, config->server_listen_backlog, hub);
if (!hub->server)
{ {
hub_free(hub); hub_free(hub);
LOG_FATAL("Unable to start hub service");
return 0; return 0;
} }
LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", net_get_local_address(hub->server->sd), config->server_port);
af = addr.ss_family;
if (af == AF_INET)
{
net_address_to_string(AF_INET, &((struct sockaddr_in*) &addr)->sin_addr, address_buf, INET6_ADDRSTRLEN);
}
else if (af == AF_INET6)
{
net_address_to_string(AF_INET6, &((struct sockaddr_in6*) &addr)->sin6_addr, address_buf, INET6_ADDRSTRLEN);
}
LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
if (server_tcp == -1)
{
hub_free(hub);
return 0;
}
ret = net_set_reuseaddress(server_tcp, 1);
if (ret == -1)
{
hub_free(hub);
net_close(server_tcp);
return 0;
}
ret = net_set_nonblocking(server_tcp, 1);
if (ret == -1)
{
hub_free(hub);
net_close(server_tcp);
return 0;
}
ret = net_bind(server_tcp, (struct sockaddr*) &addr, sockaddr_size);
if (ret == -1)
{
LOG_FATAL("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
hub_free(hub);
net_close(server_tcp);
return 0;
}
ret = net_listen(server_tcp, config->server_listen_backlog);
if (ret == -1)
{
LOG_FATAL("hub_start_service(): Unable to listen to socket");
hub_free(hub);
net_close(server_tcp);
return 0;
}
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
if (config->tls_enable) if (config->tls_enable)
@@ -549,22 +552,21 @@ struct hub_info* hub_start_service(struct hub_config* config)
} }
#endif #endif
hub->config = config; hub->config = config;
hub->users = NULL; hub->users = NULL;
if (uman_init(hub) == -1) if (uman_init(hub) == -1)
{ {
net_con_close(hub->server);
hub_free(hub); hub_free(hub);
net_close(server_tcp);
return 0; return 0;
} }
if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1) if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
{ {
net_con_close(hub->server);
uman_shutdown(hub); uman_shutdown(hub);
hub_free(hub); hub_free(hub);
net_close(server_tcp);
return 0; return 0;
} }
@@ -572,11 +574,11 @@ struct hub_info* hub_start_service(struct hub_config* config)
hub->sendbuf = hub_malloc(MAX_SEND_BUF); hub->sendbuf = hub_malloc(MAX_SEND_BUF);
if (!hub->recvbuf || !hub->sendbuf) if (!hub->recvbuf || !hub->sendbuf)
{ {
net_con_close(hub->server);
hub_free(hub->recvbuf); hub_free(hub->recvbuf);
hub_free(hub->sendbuf); hub_free(hub->sendbuf);
uman_shutdown(hub); uman_shutdown(hub);
hub_free(hub); hub_free(hub);
net_close(server_tcp);
return 0; return 0;
} }
@@ -584,21 +586,18 @@ struct hub_info* hub_start_service(struct hub_config* config)
hub->logout_info = (struct linked_list*) list_create(); hub->logout_info = (struct linked_list*) list_create();
if (!hub->chat_history) if (!hub->chat_history)
{ {
net_con_close(hub->server);
list_destroy(hub->chat_history); list_destroy(hub->chat_history);
list_destroy(hub->logout_info); list_destroy(hub->logout_info);
hub_free(hub->recvbuf); hub_free(hub->recvbuf);
hub_free(hub->sendbuf); hub_free(hub->sendbuf);
uman_shutdown(hub); uman_shutdown(hub);
hub_free(hub); hub_free(hub);
net_close(server_tcp);
return 0; return 0;
} }
hub->status = hub_status_running; hub->status = hub_status_running;
hub->server = net_con_create();
net_con_initialize(hub->server, server_tcp, net_on_accept, hub, NET_EVENT_READ);
g_hub = hub; g_hub = hub;
return hub; return hub;
} }
@@ -609,9 +608,6 @@ void hub_shutdown_service(struct hub_info* hub)
LOG_DEBUG("hub_shutdown_service()"); LOG_DEBUG("hub_shutdown_service()");
event_queue_shutdown(hub->queue); event_queue_shutdown(hub->queue);
#ifdef USE_LIBEVENT
event_del(&hub->ev_accept);
#endif
net_con_close(hub->server); net_con_close(hub->server);
hub_free(hub->server); hub_free(hub->server);
uman_shutdown(hub); uman_shutdown(hub);
@@ -669,6 +665,22 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
close(fd); close(fd);
} }
hub->command_rules = 0;
fd = (hub->config->file_rules && *hub->config->file_rules) ? open(hub->config->file_rules, 0) : -1;
if (fd != -1)
{
ret = read(fd, buf, MAX_RECV_BUF);
if (ret > 0)
{
buf[ret] = 0;
tmp = adc_msg_escape(buf);
hub->command_rules = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp));
adc_msg_add_argument(hub->command_rules, tmp);
hub_free(tmp);
}
close(fd);
}
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));
if (hub->command_support) if (hub->command_support)
{ {
@@ -697,6 +709,9 @@ void hub_free_variables(struct hub_info* hub)
if (hub->command_motd) if (hub->command_motd)
adc_msg_free(hub->command_motd); adc_msg_free(hub->command_motd);
if (hub->command_rules)
adc_msg_free(hub->command_rules);
adc_msg_free(hub->command_support); adc_msg_free(hub->command_support);
} }

View File

@@ -91,10 +91,6 @@ struct hub_logout_info
struct hub_info struct hub_info
{ {
struct net_connection* server; struct net_connection* server;
#ifdef USE_LIBEVENT
struct event ev_accept;
struct event ev_timer;
#endif
struct hub_stats stats; struct hub_stats stats;
struct event_queue* queue; struct event_queue* queue;
struct hub_config* config; struct hub_config* config;
@@ -103,6 +99,7 @@ struct hub_info
struct adc_message* command_info; /* The hub's INF command */ struct adc_message* command_info; /* The hub's INF command */
struct adc_message* command_support; /* The hub's SUP command */ struct adc_message* command_support; /* The hub's SUP command */
struct adc_message* command_motd; /* The message of the day */ struct adc_message* command_motd; /* The message of the day */
struct adc_message* command_rules; /* The hub rules */
struct adc_message* command_banner; /* The default welcome message */ struct adc_message* command_banner; /* The default welcome message */
time_t tm_started; time_t tm_started;
int status; int status;
@@ -203,8 +200,15 @@ extern void hub_send_handshake(struct hub_info* hub, struct hub_user* u);
/** /**
* Send a welcome message containing the message of the day to * Send a welcome message containing the message of the day to
* one particular user. This can be sent in any point in time. * one particular user. This can be sent in any point in time.
* @return 1 if the motd were sent.
*/ */
extern void hub_send_motd(struct hub_info* hub, struct hub_user* u); extern int hub_send_motd(struct hub_info* hub, struct hub_user* u);
/**
* Send the rules if configured.
* @return 1 if the rules were sent.
*/
extern int hub_send_rules(struct hub_info* hub, struct hub_user* u);
/** /**
* Send a password challenge to a user. * Send a password challenge to a user.

View File

@@ -68,6 +68,10 @@ void on_login_success(struct hub_info* hub, struct hub_user* u)
if (user_is_logged_in(u)) /* Previous send() can fail! */ if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(hub, u); hub_send_motd(hub, u);
/* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_rules(hub, u);
/* reset timeout */ /* reset timeout */
net_con_clear_timeout(u->connection); net_con_clear_timeout(u->connection);
} }

View File

@@ -33,13 +33,13 @@ static const char* arg_pid = 0;
static int arg_log_syslog = 0; static int arg_log_syslog = 0;
#if !defined(WIN32) && defined(USE_LIBEVENT) #if !defined(WIN32)
void hub_handle_signal(int fd, short events, void* arg) extern struct hub_info* g_hub;
void hub_handle_signal(int sig)
{ {
struct hub_info* hub = (struct hub_info*) arg; struct hub_info* hub = g_hub;
int signal = fd;
switch (signal) switch (sig)
{ {
case SIGINT: case SIGINT:
LOG_INFO("Interrupted. Shutting down..."); LOG_INFO("Interrupted. Shutting down...");
@@ -65,7 +65,6 @@ void hub_handle_signal(int fd, short events, void* arg)
} }
} }
static struct event signal_events[10];
static int signals[] = static int signals[] =
{ {
SIGINT, /* Interrupt the application */ SIGINT, /* Interrupt the application */
@@ -77,11 +76,16 @@ static int signals[] =
void setup_signal_handlers(struct hub_info* hub) void setup_signal_handlers(struct hub_info* hub)
{ {
sigset_t sig_set;
sigemptyset(&sig_set);
struct sigaction act;
act.sa_mask = sig_set;
act.sa_flags = SA_ONSTACK | SA_RESTART;
act.sa_handler = hub_handle_signal;
int i = 0; int i = 0;
for (i = 0; signals[i]; i++) for (i = 0; signals[i]; i++)
{ {
signal_set(&signal_events[i], signals[i], hub_handle_signal, hub); if (sigaction(signals[i], &act, 0) != 0)
if (signal_add(&signal_events[i], NULL))
{ {
LOG_ERROR("Error setting signal handler %d", signals[i]); LOG_ERROR("Error setting signal handler %d", signals[i]);
} }
@@ -90,14 +94,8 @@ void setup_signal_handlers(struct hub_info* hub)
void shutdown_signal_handlers(struct hub_info* hub) void shutdown_signal_handlers(struct hub_info* hub)
{ {
int i = 0;
for (i = 0; signals[i]; i++)
{
signal_del(&signal_events[i]);
}
} }
#endif /* !WIN32 */
#endif /* !WIN32 && USE_LIBEVENT*/
int main_loop() int main_loop()
@@ -133,7 +131,7 @@ int main_loop()
hub = hub_start_service(&configuration); hub = hub_start_service(&configuration);
if (!hub) if (!hub)
return -1; return -1;
#if !defined(WIN32) && defined(USE_LIBEVENT) #if !defined(WIN32)
setup_signal_handlers(hub); setup_signal_handlers(hub);
#endif #endif
} }
@@ -148,7 +146,7 @@ int main_loop()
} while (hub->status == hub_status_restart); } while (hub->status == hub_status_restart);
#if !defined(WIN32) && defined(USE_LIBEVENT) #if !defined(WIN32)
shutdown_signal_handlers(hub); shutdown_signal_handlers(hub);
#endif #endif

View File

@@ -27,7 +27,7 @@ extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ #ifdef DEBUG_SENDQ
void debug_sendq_send(struct hub_user* user, int sent, int total) void debug_sendq_send(struct hub_user* user, int sent, int total)
{ {
LOG_DUMP("SEND: sd=%d, %d/%d bytes\n", user->net.connection.sd, sent, total); LOG_DUMP("SEND: sd=%d, %d/%d bytes\n", user->connection->sd, sent, total);
if (sent == -1) if (sent == -1)
{ {
int err = net_error(); int err = net_error();
@@ -162,26 +162,16 @@ void net_event(struct net_connection* con, int event, void *arg)
int flag_close = 0; int flag_close = 0;
#ifdef DEBUG_SENDQ #ifdef DEBUG_SENDQ
LOG_TRACE("net_event() : fd=%d, ev=%d, arg=%p", fd, (int) event, arg); LOG_TRACE("net_event() : fd=%d, ev=%d, arg=%p", con->sd, (int) event, arg);
#endif #endif
if (event == NET_EVENT_SOCKERROR) if (event == NET_EVENT_TIMEOUT)
{
hub_disconnect_user(g_hub, user, quit_socket_error);
return;
}
else if (event == NET_EVENT_CLOSED)
{
hub_disconnect_user(g_hub, user, quit_disconnected);
return;
}
else if (event == NET_EVENT_TIMEOUT)
{ {
if (user_is_connecting(user)) if (user_is_connecting(user))
{ {
hub_disconnect_user(g_hub, user, quit_timeout); hub_disconnect_user(g_hub, user, quit_timeout);
return;
} }
return;
} }
if (event & NET_EVENT_READ) if (event & NET_EVENT_READ)
@@ -238,7 +228,7 @@ void net_on_accept(struct net_connection* con, int event, void *arg)
if (acl_is_ip_banned(hub->acl, addr)) if (acl_is_ip_banned(hub->acl, addr))
{ {
LOG_INFO("Denied [%s] (IP banned)", addr); LOG_INFO("Denied [%s] (IP banned)", addr);
net_close(fd); net_con_close(con);
continue; continue;
} }
@@ -246,7 +236,7 @@ void net_on_accept(struct net_connection* con, int event, void *arg)
if (!probe) if (!probe)
{ {
LOG_ERROR("Unable to create probe after socket accepted. Out of memory?"); LOG_ERROR("Unable to create probe after socket accepted. Out of memory?");
net_close(fd); net_con_close(con);
break; break;
} }
} }

View File

@@ -26,8 +26,7 @@ static char probe_recvbuf[PROBE_RECV_SIZE];
static void probe_net_event(struct net_connection* con, int events, void *arg) static void probe_net_event(struct net_connection* con, int events, void *arg)
{ {
struct hub_probe* probe = (struct hub_probe*) net_con_get_ptr(con); struct hub_probe* probe = (struct hub_probe*) net_con_get_ptr(con);
if (events == NET_EVENT_TIMEOUT)
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED || events == NET_EVENT_TIMEOUT)
{ {
probe_destroy(probe); probe_destroy(probe);
return; return;

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-2010, 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

@@ -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-2010, 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
@@ -45,6 +45,7 @@ enum user_flags
feature_ping = 0x00000080, /** PING: Hub pinger information extension */ feature_ping = 0x00000080, /** PING: Hub pinger information extension */
feature_link = 0x00000100, /** LINK: Hub link (not supported) */ feature_link = 0x00000100, /** LINK: Hub link (not supported) */
feature_adcs = 0x00000200, /** ADCS: ADC over TLS/SSL */ feature_adcs = 0x00000200, /** ADCS: ADC over TLS/SSL */
flag_muted = 0x00800000, /** User is muted (cannot chat) */
flag_ignore = 0x01000000, /** Ignore further reads */ flag_ignore = 0x01000000, /** Ignore further reads */
flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */ flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */
flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */ flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */

View File

@@ -19,8 +19,6 @@
#include "uhub.h" #include "uhub.h"
#define USERMANAGER_TIMER
/* /*
* This callback function is used to clear user objects from the userlist. * This callback function is used to clear user objects from the userlist.
* Should only be used in uman_shutdown(). * Should only be used in uman_shutdown().
@@ -40,7 +38,6 @@ static void clear_user_list_callback(void* ptr)
} }
} }
void uman_update_stats(struct hub_info* hub) void uman_update_stats(struct hub_info* hub)
{ {
const int factor = TIMEOUT_STATS; const int factor = TIMEOUT_STATS;
@@ -58,7 +55,6 @@ void uman_update_stats(struct hub_info* hub)
net_stats_reset(); net_stats_reset();
} }
void uman_print_stats(struct hub_info* hub) void uman_print_stats(struct hub_info* hub)
{ {
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)", 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)",
@@ -70,28 +66,16 @@ void uman_print_stats(struct hub_info* hub)
(int) hub->stats.net_rx_peak / 1024); (int) hub->stats.net_rx_peak / 1024);
} }
#ifdef USERMANAGER_TIMER static void timer_statistics(struct timeout_evt* t)
#ifdef USE_LIBEVENT
static void timer_statistics(int fd, short ev, void *arg)
{ {
struct hub_info* hub = (struct hub_info*) arg; struct hub_info* hub = (struct hub_info*) t->ptr;
struct timeval timeout = { TIMEOUT_STATS, 0 };
uman_update_stats(hub); uman_update_stats(hub);
evtimer_set(&hub->ev_timer, timer_statistics, hub); timeout_queue_reschedule(net_backend_get_timeout_queue(), hub->users->timeout, TIMEOUT_STATS);
evtimer_add(&hub->ev_timer, &timeout);
} }
#endif
#endif
int uman_init(struct hub_info* hub) int uman_init(struct hub_info* hub)
{ {
struct hub_user_manager* users = NULL; struct hub_user_manager* users = NULL;
#ifdef USERMANAGER_TIMER
#ifdef USE_LIBEVENT
struct timeval timeout = { TIMEOUT_STATS, 0 };
#endif
#endif
if (!hub) if (!hub)
return -1; return -1;
@@ -109,17 +93,11 @@ int uman_init(struct hub_info* hub)
return -1; return -1;
} }
hub->users = users; 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);
#ifdef USERMANAGER_TIMER hub->users = users;
#ifdef USE_LIBEVENT
if (net_get_evbase())
{
evtimer_set(&hub->ev_timer, timer_statistics, hub);
evtimer_add(&hub->ev_timer, &timeout);
}
#endif
#endif // 0
return 0; return 0;
} }
@@ -129,12 +107,8 @@ int uman_shutdown(struct hub_info* hub)
if (!hub || !hub->users) if (!hub || !hub->users)
return -1; return -1;
#ifdef USERMANAGER_TIMER timeout_queue_remove(net_backend_get_timeout_queue(), hub->users->timeout);
#ifdef USE_LIBEVENT hub_free(hub->users->timeout);
if (evtimer_pending(&hub->ev_timer, 0))
evtimer_del(&hub->ev_timer);
#endif
#endif
if (hub->users->list) if (hub->users->list)
{ {
@@ -145,6 +119,7 @@ int uman_shutdown(struct hub_info* hub)
hub_free(hub->users); hub_free(hub->users);
hub->users = 0; hub->users = 0;
return 0; return 0;
} }

View File

@@ -28,6 +28,7 @@ struct hub_user_manager
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */ 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." */ uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct linked_list* list; /**<< "Contains all logged in users" */ struct linked_list* list; /**<< "Contains all logged in users" */
struct timeout_evt* timeout; /**<< "Timeout handler for statistics" */
}; };
/** /**

63
src/network/backend.c Normal file
View File

@@ -0,0 +1,63 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, 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/connection.h"
struct net_cleanup_handler
{
size_t num;
size_t max;
struct net_connection** queue;
};
struct net_cleanup_handler* net_cleanup_initialize(size_t max)
{
struct net_cleanup_handler* handler = (struct net_cleanup_handler*) hub_malloc(sizeof(struct net_cleanup_handler));
handler->num = 0;
handler->max = max;
handler->queue = hub_malloc_zero(sizeof(struct net_connection*) * max);
return handler;
}
void net_cleanup_shutdown(struct net_cleanup_handler* handler)
{
hub_free(handler->queue);
hub_free(handler);
}
void net_cleanup_delayed_free(struct net_cleanup_handler* handler, struct net_connection* con)
{
handler->queue[handler->num++] = con;
con->flags |= NET_CLEANUP;
}
void net_cleanup_process(struct net_cleanup_handler* handler)
{
size_t n;
for (n = 0; n < handler->num; n++)
{
struct net_connection* con = handler->queue[n];
LOG_TRACE("net_cleanup_process: free: %p", con);
hub_free(con);
}
handler->num = 0;
}

View File

@@ -20,6 +20,9 @@
#ifndef HAVE_UHUB_NETWORK_BACKEND_H #ifndef HAVE_UHUB_NETWORK_BACKEND_H
#define HAVE_UHUB_NETWORK_BACKEND_H #define HAVE_UHUB_NETWORK_BACKEND_H
struct net_cleanup_handler;
struct net_connection;
/** /**
* Initialize the network backend. * Initialize the network backend.
* Returns 1 on success, or 0 on failure. * Returns 1 on success, or 0 on failure.
@@ -36,4 +39,15 @@ extern void net_backend_shutdown();
*/ */
extern int net_backend_process(); extern int net_backend_process();
extern struct timeout_queue* net_backend_get_timeout_queue();
struct net_cleanup_handler* net_cleanup_initialize(size_t max);
void net_cleanup_shutdown(struct net_cleanup_handler* handler);
void net_cleanup_delayed_free(struct net_cleanup_handler* handler, struct net_connection* con);
void net_cleanup_process(struct net_cleanup_handler* handler);
#endif /* HAVE_UHUB_NETWORK_BACKEND_H */ #endif /* HAVE_UHUB_NETWORK_BACKEND_H */

View File

@@ -1,37 +1,51 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, 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/>.
*
*/
#define NET_WANT_READ NET_EVENT_READ #define NET_WANT_READ NET_EVENT_READ
#define NET_WANT_WRITE NET_EVENT_WRITE #define NET_WANT_WRITE NET_EVENT_WRITE
#define NET_WANT_ACCEPT 0x0008 #define NET_WANT_ACCEPT NET_EVENT_READ
#define NET_WANT_SSL_READ 0x0010 #define NET_WANT_SSL_READ 0x0010
#define NET_WANT_SSL_WRITE 0x0020 #define NET_WANT_SSL_WRITE 0x0020
#define NET_WANT_SSL_ACCEPT 0x0040 #define NET_WANT_SSL_ACCEPT 0x0040
#define NET_WANT_SSL_CONNECT 0x0080 #define NET_WANT_SSL_CONNECT 0x0080
#define NET_WANT_SSL_X509_LOOKUP 0x0100 #define NET_WANT_SSL_X509_LOOKUP 0x0100
#define NET_PROCESSING_BUSY 0x8000 #define NET_CLEANUP 0x8000
#define NET_CLEANUP 0x4000
#define NET_INITIALIZED 0x2000
#define NET_TIMER_ENABLED 0x1000
/* FIXME: Meant for debugging */
#define NET_EVENT_SET 0x0800
#define NET_CON_STRUCT_BASIC \ #define NET_CON_STRUCT_BASIC \
int sd; /** socket descriptor */ \ int sd; /** socket descriptor */ \
uint32_t flags; /** Connection flags */ \ uint32_t flags; /** Connection flags */ \
void* ptr; /** data pointer */ \ void* ptr; /** data pointer */ \
net_connection_cb callback; /** Callback function */ \ net_connection_cb callback; /** Callback function */ \
struct timeout_evt* timeout; /** timeout event handler */
#define NET_CON_STRUCT_SSL \ #define NET_CON_STRUCT_SSL \
SSL* ssl; /** SSL handle */ \ 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. */ \ size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ \
#ifdef USE_SSL #ifdef SSL_SUPPORT
#define NET_CON_STRUCT_COMMON \ #define NET_CON_STRUCT_COMMON \
NET_CON_STRUCT_BASIC \ NET_CON_STRUCT_BASIC \
NET_CON_STRUCT_SSL NET_CON_STRUCT_SSL
#else #else
#define NET_CON_STRUCT_COMMON \ #define NET_CON_STRUCT_COMMON \
NET_CON_STRUCT_BASIC NET_CON_STRUCT_BASIC
#endif #endif /* SSL_SUPPORT */

View File

@@ -21,39 +21,39 @@
#include "network/common.h" #include "network/common.h"
#ifdef SSL_SUPPORT #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) static int handle_openssl_error(struct net_connection* con, int ret)
{ {
uhub_assert(con); uhub_assert(con);
int error = SSL_get_error(net_con_get_ssl(con), ret); int error = SSL_get_error(con->ssl, ret);
switch (error) switch (error)
{ {
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error); LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error);
con->ssl_state = tls_st_error;
return -1; return -1;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error); LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error);
net_con_update(con, NET_EVENT_READ | NET_WANT_SSL_READ); con->flags |= NET_WANT_SSL_READ;
net_con_update(con, NET_EVENT_READ);
return 0; return 0;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error); LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_WRITE); con->flags |= NET_WANT_SSL_WRITE;
return 0; net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE);
case SSL_ERROR_WANT_CONNECT:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_CONNECT", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_CONNECT);
return 0;
case SSL_ERROR_WANT_ACCEPT:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_ACCEPT", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_ACCEPT);
return 0;
case SSL_ERROR_WANT_X509_LOOKUP:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_X509_LOOKUP", ret, error);
return 0; return 0;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
@@ -67,6 +67,7 @@ static int handle_openssl_error(struct net_connection* con, int ret)
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error); LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error);
/* internal openssl error */ /* internal openssl error */
con->ssl_state = tls_st_error;
return -1; return -1;
} }
@@ -76,14 +77,15 @@ static int handle_openssl_error(struct net_connection* con, int ret)
ssize_t net_con_ssl_accept(struct net_connection* con) ssize_t net_con_ssl_accept(struct net_connection* con)
{ {
uhub_assert(con); uhub_assert(con);
con->ssl_state = tls_st_accepting;
ssize_t ret = SSL_accept(net_con_get_ssl(con)); ssize_t ret = SSL_accept(con->ssl);
#ifdef NETWORK_DUMP_DEBUG #ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_accept() ret=%d", ret); LOG_PROTO("SSL_accept() ret=%d", ret);
#endif #endif
if (ret > 0) if (ret > 0)
{ {
net_con_update(con, NET_EVENT_READ); net_con_update(con, NET_EVENT_READ);
con->ssl_state = tls_st_connected;
} }
else else
{ {
@@ -96,12 +98,14 @@ ssize_t net_con_ssl_connect(struct net_connection* con)
{ {
uhub_assert(con); uhub_assert(con);
ssize_t ret = SSL_connect(net_con_get_ssl(con)); con->ssl_state = tls_st_connecting;
ssize_t ret = SSL_connect(con->ssl);
#ifdef NETWORK_DUMP_DEBUG #ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("SSL_connect() ret=%d", ret); LOG_PROTO("SSL_connect() ret=%d", ret);
#endif #endif
if (ret > 0) if (ret > 0)
{ {
con->ssl_state = tls_st_connected;
net_con_update(con, NET_EVENT_READ); net_con_update(con, NET_EVENT_READ);
} }
else else
@@ -119,14 +123,14 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode
if (ssl_mode == net_con_ssl_mode_server) if (ssl_mode == net_con_ssl_mode_server)
{ {
ssl = SSL_new(ssl_ctx); ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, net_con_get_sd(con)); SSL_set_fd(ssl, con->sd);
net_con_set_ssl(con, ssl); net_con_set_ssl(con, ssl);
return net_con_ssl_accept(con); return net_con_ssl_accept(con);
} }
else else
{ {
ssl = SSL_new(SSL_CTX_new(TLSv1_method())); ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
SSL_set_fd(ssl, net_con_get_sd(con)); SSL_set_fd(ssl, con->sd);
net_con_set_ssl(con, ssl); net_con_set_ssl(con, ssl);
return net_con_ssl_connect(con); return net_con_ssl_connect(con);
} }
@@ -136,28 +140,42 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode
ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{ {
int ret = net_send(net_con_get_sd(con), buf, len, UHUB_SEND_SIGNAL); int ret;
#ifdef SSL_SUPPORT
if (!con->ssl)
{
#endif
ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL);
if (ret == -1) if (ret == -1)
{ {
if (net_error() == EWOULDBLOCK || net_error() == EINTR) if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0; return 0;
return -1; return -1;
} }
#ifdef SSL_SUPPORT
}
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);
}
}
#endif
return ret; return ret;
} }
ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{ {
uhub_assert(con); int ret;
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
if (!net_con_is_ssl(con)) if (!net_con_is_ssl(con))
{ {
#endif #endif
int ret = net_recv(net_con_get_sd(con), buf, len, 0); ret = net_recv(con->sd, buf, len, 0);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_recv: ret=%d", ret);
#endif
if (ret == -1) if (ret == -1)
{ {
if (net_error() == EWOULDBLOCK || net_error() == EINTR) if (net_error() == EWOULDBLOCK || net_error() == EINTR)
@@ -168,16 +186,15 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{ {
return -1; return -1;
} }
return ret;
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
} }
else else
{ {
int ret = SSL_read(net_con_get_ssl(con), buf, len); if (con->ssl_state == tls_st_error)
#ifdef NETWORK_DUMP_DEBUG return -1;
LOG_PROTO("net_recv: ret=%d", ret);
#endif 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) if (ret > 0)
{ {
net_con_update(con, NET_EVENT_READ); net_con_update(con, NET_EVENT_READ);
@@ -186,14 +203,14 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{ {
return -handle_openssl_error(con, ret); return -handle_openssl_error(con, ret);
} }
return ret;
} }
#endif #endif
return ret;
} }
ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len) ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
{ {
int ret = net_recv(net_con_get_sd(con), buf, len, MSG_PEEK); int ret = net_recv(con->sd, buf, len, MSG_PEEK);
if (ret == -1) if (ret == -1)
{ {
if (net_error() == EWOULDBLOCK || net_error() == EINTR) if (net_error() == EWOULDBLOCK || net_error() == EINTR)
@@ -205,6 +222,102 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
return ret; return ret;
} }
#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;
}
#endif /* SSL_SUPPORT */
int net_con_get_sd(struct net_connection* con)
{
return con->sd;
}
void* net_con_get_ptr(struct net_connection* con)
{
return con->ptr;
}
void net_con_callback(struct net_connection* con, int events)
{
if (con->flags & NET_CLEANUP)
return;
if (events == NET_EVENT_TIMEOUT)
{
LOG_TRACE("net_con_callback(%p, TIMEOUT", con);
con->callback(con, events, con->ptr);
return;
}
#ifdef SSL_SUPPORT
if (!con->ssl)
{
#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

@@ -21,17 +21,22 @@
#define HAVE_UHUB_NETWORK_CONNECTION_H #define HAVE_UHUB_NETWORK_CONNECTION_H
#include "uhub.h" #include "uhub.h"
#include "network/common.h"
#include "network/backend.h" #include "network/backend.h"
#define NET_EVENT_TIMEOUT 0x0001 #define NET_EVENT_TIMEOUT 0x0001
#define NET_EVENT_READ 0x0002 #define NET_EVENT_READ 0x0002
#define NET_EVENT_WRITE 0x0004 #define NET_EVENT_WRITE 0x0004
#define NET_EVENT_SOCKERROR 0x1000 /* Socket error, closed */
#define NET_EVENT_CLOSED 0x2000 /* Socket closed */
struct net_connection; struct net_connection;
typedef void (*net_connection_cb)(struct net_connection*, int event, void* ptr); typedef void (*net_connection_cb)(struct net_connection*, int event, void* ptr);
struct net_connection
{
NET_CON_STRUCT_COMMON
};
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);
@@ -40,14 +45,14 @@ 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);
extern void net_con_update(struct net_connection* con, int events); extern void net_con_update(struct net_connection* con, int events);
extern void net_con_callback(struct net_connection* con, int events);
/** /**
* Close the connection. * Close the connection.
* This will ensure a connection is closed properly and will generate a NET_EVENT_DESTROYED event which indicates * This will ensure a connection is closed properly and will generate a NET_EVENT_DESTROYED event which indicates
* that the con can safely be deleted (or set to NULL). * that the con can safely be deleted (or set to NULL).
* @returns 1 if the memory pointed to by con can be freed immediately, or 0 if it needs to go through the NET_EVENT_DESTROYED event.
*/ */
extern int net_con_close(struct net_connection* con); extern void net_con_close(struct net_connection* con);
/** /**
* Send data * Send data

View File

@@ -27,18 +27,10 @@
#define EPOLL_EVBUFFER 512 #define EPOLL_EVBUFFER 512
struct net_connection struct net_connection_epoll
{ {
int sd; NET_CON_STRUCT_COMMON
uint32_t flags;
net_connection_cb callback;
void* ptr;
struct epoll_event ev; struct epoll_event ev;
struct timeout_evt* timeout;
#ifdef SSL_SUPPORT
SSL* ssl;
size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */
#endif
}; };
struct net_backend struct net_backend
@@ -46,15 +38,16 @@ struct net_backend
int epfd; int epfd;
size_t num; size_t num;
size_t max; size_t max;
struct net_connection** conns; struct net_connection_epoll** conns;
struct epoll_event events[EPOLL_EVBUFFER]; struct epoll_event events[EPOLL_EVBUFFER];
time_t now; time_t now;
struct timeout_queue timeout_queue; struct timeout_queue timeout_queue;
struct net_cleanup_handler* cleaner;
}; };
static struct net_backend* g_backend = 0; static struct net_backend* g_backend = 0;
static void net_con_print(const char* prefix, struct net_connection* con) static void net_con_print(const char* prefix, struct net_connection_epoll* con)
{ {
char buf[512]; char buf[512];
int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, ev={ events=%s%s, data.ptr=%p }", int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, ev={ events=%s%s, data.ptr=%p }",
@@ -87,11 +80,12 @@ int net_backend_initialize()
g_backend->num = 0; g_backend->num = 0;
g_backend->max = max; g_backend->max = max;
g_backend->conns = hub_malloc_zero(sizeof(struct net_connection*) * max); g_backend->conns = hub_malloc_zero(sizeof(struct net_connection_epoll*) * max);
memset(g_backend->events, 0, sizeof(g_backend->events)); memset(g_backend->events, 0, sizeof(g_backend->events));
g_backend->now = time(0); g_backend->now = time(0);
timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* look max 10 minutes into the future. */ timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* look max 10 minutes into the future. */
g_backend->cleaner = net_cleanup_initialize(max);
return 1; return 1;
} }
@@ -101,6 +95,8 @@ int net_backend_initialize()
void net_backend_shutdown() void net_backend_shutdown()
{ {
close(g_backend->epfd); close(g_backend->epfd);
timeout_queue_shutdown(&g_backend->timeout_queue);
net_cleanup_shutdown(g_backend->cleaner);
hub_free(g_backend->conns); hub_free(g_backend->conns);
hub_free(g_backend); hub_free(g_backend);
} }
@@ -111,8 +107,13 @@ void net_backend_shutdown()
int net_backend_process() int net_backend_process()
{ {
int n; int n;
LOG_TRACE("epoll_wait: fd=%d, events=%x, max=%zu", g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER)); size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
int res = epoll_wait(g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER), 1000); LOG_TRACE("epoll_wait: fd=%d, events=%x, max=%zu, seconds=%d", g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER), (int) secs);
int res = epoll_wait(g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER), secs * 1000);
g_backend->now = time(0);
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
if (res == -1) if (res == -1)
{ {
LOG_WARN("epoll_wait returned -1"); LOG_WARN("epoll_wait returned -1");
@@ -121,19 +122,25 @@ int net_backend_process()
for (n = 0; n < res; n++) for (n = 0; n < res; n++)
{ {
struct net_connection* con = (struct net_connection*) g_backend->events[n].data.ptr; struct net_connection_epoll* con = (struct net_connection_epoll*) g_backend->events[n].data.ptr;
int ev = 0; int ev = 0;
if (g_backend->events[n].events & EPOLLIN) ev |= NET_EVENT_READ; if (g_backend->events[n].events & EPOLLIN) ev |= NET_EVENT_READ;
if (g_backend->events[n].events & EPOLLOUT) ev |= NET_EVENT_WRITE; if (g_backend->events[n].events & EPOLLOUT) ev |= NET_EVENT_WRITE;
con->callback(con, ev, con->ptr); net_con_callback((struct net_connection*) con, ev);
} }
net_cleanup_process(g_backend->cleaner);
return 1; return 1;
} }
struct timeout_queue* net_backend_get_timeout_queue()
{
return &g_backend->timeout_queue;
}
struct net_connection* net_con_create() struct net_connection* net_con_create()
{ {
struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection)); struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection_epoll));
con->sd = -1; con->sd = -1;
return con; return con;
} }
@@ -143,10 +150,11 @@ void net_con_destroy(struct net_connection* con)
hub_free(con); hub_free(con);
} }
void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events) void net_con_initialize(struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr, int events)
{ {
struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
con->sd = sd; con->sd = sd;
con->flags = NET_INITIALIZED; con->flags = 0;
con->callback = callback; con->callback = callback;
con->ev.events = 0; con->ev.events = 0;
con->ptr = (void*) ptr; con->ptr = (void*) ptr;
@@ -176,34 +184,17 @@ void net_con_reinitialize(struct net_connection* con, net_connection_cb callback
net_con_update(con, events); net_con_update(con, events);
} }
void net_con_update(struct net_connection* con, int events) void net_con_update(struct net_connection* con_, int events)
{ {
con->ev.events = 0; struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN; int newev = 0;
if (events & NET_EVENT_WRITE) con->ev.events |= EPOLLOUT; if (events & NET_EVENT_READ) newev |= EPOLLIN;
if (events & NET_EVENT_WRITE) newev |= EPOLLOUT;
#ifdef SSL_SUPPORT if (newev == con->ev.events)
if (events & NET_WANT_SSL_WRITE) return;
con->flags |= NET_WANT_SSL_WRITE;
else
con->flags &= ~NET_WANT_SSL_WRITE;
if (events & NET_WANT_SSL_READ)
con->flags |= NET_WANT_SSL_READ;
else
con->flags &= ~NET_WANT_SSL_READ;
if (events & NET_WANT_SSL_ACCEPT)
con->flags |= NET_WANT_SSL_ACCEPT;
else
con->flags &= ~NET_WANT_SSL_ACCEPT;
if (events & NET_WANT_SSL_CONNECT)
con->flags |= NET_WANT_SSL_CONNECT;
else
con->flags &= ~NET_WANT_SSL_CONNECT;
#endif /* SSL_SUPPORT */
con->ev.events = newev;
if (epoll_ctl(g_backend->epfd, EPOLL_CTL_MOD, con->sd, &con->ev) == -1) if (epoll_ctl(g_backend->epfd, EPOLL_CTL_MOD, con->sd, &con->ev) == -1)
{ {
LOG_TRACE("epoll_ctl() modify failed."); LOG_TRACE("epoll_ctl() modify failed.");
@@ -211,12 +202,11 @@ void net_con_update(struct net_connection* con, int events)
net_con_print("MOD", con); net_con_print("MOD", con);
} }
int net_con_close(struct net_connection* con) void net_con_close(struct net_connection* con_)
{ {
if (!(con->flags & NET_INITIALIZED)) struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
return 0; if (con->flags & NET_CLEANUP)
return;
con->flags &= ~NET_INITIALIZED;
if (con->sd != -1) if (con->sd != -1)
{ {
@@ -224,83 +214,18 @@ int net_con_close(struct net_connection* con)
g_backend->num--; g_backend->num--;
} }
if (timeout_evt_is_scheduled(con->timeout)) net_con_clear_timeout(con_);
{
timeout_queue_remove(&g_backend->timeout_queue, con->timeout);
hub_free(con->timeout);
con->timeout = 0;
}
if (epoll_ctl(g_backend->epfd, EPOLL_CTL_DEL, con->sd, &con->ev) == -1) if (epoll_ctl(g_backend->epfd, EPOLL_CTL_DEL, con->sd, &con->ev) == -1)
{ {
LOG_WARN("epoll_ctl() delete failed."); LOG_WARN("epoll_ctl() delete failed.");
} }
net_close(con->sd);
con->sd = -1;
net_con_print("DEL", con); net_con_print("DEL", con);
return 0; net_cleanup_delayed_free(g_backend->cleaner, con_);
}
#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;
}
#endif
int net_con_get_sd(struct net_connection* con)
{
return con->sd;
}
void* net_con_get_ptr(struct net_connection* con)
{
return con->ptr;
}
void timeout_evt_initialize(struct timeout_evt*, timeout_evt_cb, void* ptr);
void timeout_evt_reset(struct timeout_evt*);
int timeout_evt_is_scheduled(struct timeout_evt*);
static void timeout_callback(struct timeout_evt* evt)
{
struct net_connection* con = (struct net_connection*) evt->ptr;
con->callback(con, NET_EVENT_TIMEOUT, con->ptr);
}
void net_con_set_timeout(struct net_connection* con, int seconds)
{
if (!con->timeout)
{
con->timeout = hub_malloc_zero(sizeof(struct timeout_evt));
timeout_evt_initialize(con->timeout, timeout_callback, con);
timeout_queue_insert(&g_backend->timeout_queue, con->timeout, seconds);
}
else
{
timeout_queue_reschedule(&g_backend->timeout_queue, con->timeout, seconds);
}
}
void net_con_clear_timeout(struct net_connection* con)
{
if (con->timeout && timeout_evt_is_scheduled(con->timeout))
{
timeout_queue_remove(&g_backend->timeout_queue, con->timeout);
hub_free(con->timeout);
con->timeout = 0;
}
} }
#endif /* USE_EPOLL */ #endif /* USE_EPOLL */

View File

@@ -1,399 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, 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/>.
*
*/
#ifdef USE_LIBEVENT
struct net_connection
{
NET_CON_STRUCT_COMMON
struct event event; /** libevent struct for read/write events */
struct event timeout; /** Used for internal timeout handling */
};
struct net_timer
{
unsigned int initialized;
struct event timeout;
net_timeout_cb callback;
void* ptr;
};
int net_con_get_sd(struct net_connection* con)
{
return con->sd;
}
void* net_con_get_ptr(struct net_connection* con)
{
return con->ptr;
}
struct net_connection* net_con_create()
{
struct net_connection* con = (struct net_connection*) hub_malloc(sizeof(struct net_connection));
return con;
}
static inline int net_con_flag_get(struct net_connection* con, unsigned int flag)
{
return con->flags & flag;
}
static inline void net_con_flag_set(struct net_connection* con, unsigned int flag)
{
con->flags |= flag;
}
static inline void net_con_flag_unset(struct net_connection* con, unsigned int flag)
{
con->flags &= ~flag;
}
void net_con_destroy(struct net_connection* con)
{
hub_free(con);
}
static inline int net_con_convert_to_libevent_mask(int ev)
{
int events = 0;
if (ev & NET_EVENT_READ) events |= EV_READ;
if (ev & NET_EVENT_WRITE) events |= EV_WRITE;
return events;
}
static inline int net_con_convert_from_libevent_mask(int ev)
{
int events = 0;
if (ev & EV_TIMEOUT) events |= NET_EVENT_TIMEOUT;
if (ev & EV_READ) events |= NET_EVENT_READ;
if (ev & EV_WRITE) events |= NET_EVENT_WRITE;
return events;
}
static void net_con_event(int fd, short ev, void *arg);
int net_con_close(struct net_connection* con)
{
uhub_assert(con);
con->ptr = 0;
if (net_con_flag_get(con, NET_CLEANUP))
return 0;
if (net_con_flag_get(con, NET_PROCESSING_BUSY))
{
net_con_flag_set(con, NET_CLEANUP);
return 0;
}
net_con_after_close(con);
return 1;
}
static void net_con_set(struct net_connection* con)
{
uhub_assert(con);
int ev = 0;
if (net_con_flag_get(con, NET_WANT_READ | NET_WANT_SSL_READ)) ev |= EV_READ;
if (net_con_flag_get(con, NET_WANT_WRITE | NET_WANT_SSL_WRITE)) ev |= EV_WRITE;
if (net_con_flag_get(con, NET_EVENT_SET) != 0)
{
event_del(&con->event);
}
net_con_flag_set(con, NET_EVENT_SET);
LOG_MEMORY("SET: set+add: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev);
event_set(&con->event, con->sd, ev, net_con_event, con);
event_add(&con->event, 0);
net_con_flag_set(con, NET_INITIALIZED);
}
static void net_con_after_close(struct net_connection* con)
{
if (net_con_flag_get(con, NET_INITIALIZED))
{
LOG_MEMORY("DEL: close: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, -1);
net_con_flag_unset(con, NET_EVENT_SET);
event_del(&con->event);
net_con_flag_unset(con, NET_INITIALIZED);
}
net_con_clear_timeout(con);
net_close(con->sd);
con->sd = -1;
hub_free(con);
}
void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int ev)
{
uhub_assert(con);
int events = net_con_convert_to_libevent_mask(ev);
if (ev & NET_EVENT_READ) net_con_flag_set(con, NET_WANT_READ);
if (ev & NET_EVENT_WRITE) net_con_flag_set(con, NET_WANT_WRITE);
con->sd = sd;
con->flags = 0;
con->ptr = (void*) ptr;
con->callback = callback;
con->last_send = time(0);
con->last_recv = con->last_send;
if (ev)
{
uhub_assert(net_con_flag_get(con, NET_EVENT_SET) == 0);
net_con_flag_set(con, NET_EVENT_SET);
LOG_MEMORY("SET: init: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev);
event_set(&con->event, con->sd, events, net_con_event, con);
event_add(&con->event, 0);
net_con_flag_set(con, NET_INITIALIZED);
}
net_set_nonblocking(sd, 1);
net_set_nosigpipe(sd, 1);
#ifdef SSL_SUPPORT
con->ssl = NULL;
con->write_len = 0;
#endif
}
void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events)
{
uhub_assert(con);
con->callback = callback;
con->ptr = (void*) ptr;
net_con_update(con, events);
}
void net_con_update(struct net_connection* con, int ev)
{
uhub_assert(con);
if (ev & NET_EVENT_READ)
net_con_flag_set(con, NET_EVENT_READ);
else
net_con_flag_unset(con, NET_EVENT_READ);
if (ev & NET_EVENT_WRITE)
net_con_flag_set(con, NET_EVENT_WRITE);
else
net_con_flag_unset(con, NET_EVENT_WRITE);
if (!net_con_flag_get(con, NET_PROCESSING_BUSY))
{
net_con_set(con);
}
}
#define CALLBACK(CON, EVENTS) \
if (CON->callback) \
CON->callback(con, EVENTS, CON->ptr);
static void net_con_event(int fd, short ev, void *arg)
{
struct net_connection* con = (struct net_connection*) arg;
int events = net_con_convert_from_libevent_mask(ev);
if (!net_con_flag_get(con, NET_INITIALIZED))
{
return;
}
if (net_con_flag_get(con, NET_CLEANUP))
{
net_con_after_close(con);
return;
}
net_con_flag_set(con, NET_PROCESSING_BUSY);
// uhub_assert(net_con_flag_get(con, NET_EVENT_SET) != 0);
net_con_flag_unset(con, NET_EVENT_SET);
LOG_MEMORY("EVT: process: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, (int) ev);
#ifdef SSL_SUPPORT
if (!con->ssl)
{
#endif
CALLBACK(con, events);
#ifdef SSL_SUPPORT
}
else
{
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_con_event: events=%d, con=%p", ev, con);
#endif
if (ev & (EV_READ | EV_WRITE))
{
if (net_con_flag_get(con, NET_WANT_SSL_ACCEPT))
{
if (net_con_ssl_accept(con) < 0)
CALLBACK(con, NET_EVENT_SOCKERROR);
}
else if (net_con_flag_get(con, NET_WANT_SSL_CONNECT))
{
if (net_con_ssl_connect(con) < 0)
CALLBACK(con, NET_EVENT_SOCKERROR);
}
else if (ev == EV_READ && net_con_flag_get(con, NET_WANT_SSL_READ))
{
CALLBACK(con, NET_EVENT_WRITE);
}
else if (ev == EV_WRITE && net_con_flag_get(con, NET_WANT_SSL_WRITE))
{
CALLBACK(con, events & NET_EVENT_READ);
}
else
{
CALLBACK(con, events);
}
}
else
{
CALLBACK(con, events);
}
}
#endif
net_con_flag_unset(con, NET_PROCESSING_BUSY);
if (net_con_flag_get(con, NET_CLEANUP))
{
net_con_after_close(con);
}
else
{
net_con_set(con);
}
}
static void net_timer_event(int fd, short ev, void *arg)
{
struct net_timer* timer = (struct net_timer*) arg;
timer->callback(timer, timer->ptr);
}
void net_timer_initialize(struct net_timer* timer, net_timeout_cb callback, void* ptr)
{
timer->initialized = 0;
timer->callback = callback;
timer->ptr = ptr;
}
void net_timer_reset(struct net_timer* timer, int seconds)
{
struct timeval timeout = { seconds, 0 };
if (timer->initialized)
{
evtimer_del(&timer->timeout);
timer->initialized = 0;
}
evtimer_set(&timer->timeout, net_timer_event, timer);
evtimer_add(&timer->timeout, &timeout);
}
void net_timer_shutdown(struct net_timer* timer)
{
if (timer->initialized)
{
evtimer_del(&timer->timeout);
timer->initialized = 0;
}
timer->callback = 0;
timer->ptr = 0;
}
void net_con_set_timeout(struct net_connection* con, int seconds)
{
uhub_assert(con);
struct timeval timeout = { seconds, 0 };
net_con_clear_timeout(con);
evtimer_set(&con->timeout, net_con_event, con);
evtimer_add(&con->timeout, &timeout);
net_con_flag_set(con, NET_TIMER_ENABLED);
}
void net_con_clear_timeout(struct net_connection* con)
{
uhub_assert(con);
if (net_con_flag_get(con, NET_TIMER_ENABLED))
{
evtimer_del(&con->timeout);
net_con_flag_unset(con, NET_TIMER_ENABLED);
}
}
static struct event_base g_evbase = 0;
/**
* Initialize the network backend.
* Returns 1 on success, or 0 on failure.
*/
int net_backend_initialize()
{
g_evbase = event_init();
if (!g_evbase)
{
LOG_ERROR("Unable to initialize libevent.");
return 0;
}
LOG_DEBUG("Using libevent %s, backend: %s", event_get_version(), event_get_method());
return 1;
}
/**
* Shutdown the network connection backend.
*/
void net_backend_shutdown()
{
event_base_free(g_evbase);
}
/**
* Process the network backend.
*/
int net_backend_process()
{
int ret = event_base_loop(g_evbase, EVLOOP_ONCE);
if (ret != 0)
{
LOG_DEBUG("event_base_loop returned: %d", (int) ret);
}
if (ret < 0)
return 0;
return 1;
}
#endif /* USE_LIBEVENT */

View File

@@ -381,11 +381,11 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr)
{ {
char address[INET6_ADDRSTRLEN+1] = { 0, }; char address[INET6_ADDRSTRLEN+1] = { 0, };
net_address_to_string(AF_INET6, (void*) &addr6->sin6_addr, address, INET6_ADDRSTRLEN+1); net_address_to_string(AF_INET6, (void*) &addr6->sin6_addr, address, INET6_ADDRSTRLEN+1);
if (!strncmp(address, "::ffff:", 7)) if (strchr(address, '.'))
{ {
/* Hack to convert IPv6 mapped IPv4 addresses to true IPv4 addresses */ /* Hack to convert IPv6 mapped IPv4 addresses to true IPv4 addresses */
net_string_to_address(AF_INET, address + 7, (void*) &ipaddr->internal_ip_data.in);
ipaddr->af = AF_INET; ipaddr->af = AF_INET;
net_string_to_address(AF_INET, address, (void*) &ipaddr->internal_ip_data.in);
} }
else else
{ {
@@ -526,7 +526,15 @@ const char* net_address_to_string(int af, const void* src, char* dst, socklen_t
return NULL; return NULL;
#else #else
return inet_ntop(af, src, dst, cnt); if (inet_ntop(af, src, dst, cnt))
{
if (af == AF_INET6 && strncmp(dst, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
{
memmove(dst, dst + 7, cnt - 7);
}
return dst;
}
return NULL;
#endif #endif
} }
@@ -573,9 +581,6 @@ int net_string_to_address(int af, const char* src, void* dst)
#endif #endif
} }
const char* net_get_peer_address(int fd) const char* net_get_peer_address(int fd)
{ {
static char address[INET6_ADDRSTRLEN+1]; static char address[INET6_ADDRSTRLEN+1];
@@ -598,17 +603,12 @@ const char* net_get_peer_address(int fd)
if (af == AF_INET6) if (af == AF_INET6)
{ {
net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN); net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
if (strncmp(address, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
{
return &address[7];
}
return address;
} }
else else
{ {
net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN); net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
return address;
} }
return address;
} }
else else
{ {
@@ -619,6 +619,45 @@ const char* net_get_peer_address(int fd)
return "0.0.0.0"; return "0.0.0.0";
} }
const char* net_get_local_address(int fd)
{
static char address[INET6_ADDRSTRLEN+1];
struct sockaddr_storage storage;
struct sockaddr_in6* name6;
struct sockaddr_in* name4;
struct sockaddr* name;
memset(address, 0, INET6_ADDRSTRLEN);
socklen_t namelen = sizeof(struct sockaddr_storage);
memset(&storage, 0, namelen);
name6 = (struct sockaddr_in6*) &storage;
name4 = (struct sockaddr_in*) &storage;
name = (struct sockaddr*) &storage;
if (getsockname(fd, (struct sockaddr*) name, &namelen) != -1)
{
int af = name4->sin_family;
if (af == AF_INET6)
{
net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
}
else
{
net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
}
return address;
}
else
{
net_error_out(fd, "net_get_local_address");
net_stats_add_error();
}
return "0.0.0.0";
}
ssize_t net_recv(int fd, void* buf, size_t len, int flags) ssize_t net_recv(int fd, void* buf, size_t len, int flags)
{ {

View File

@@ -224,6 +224,8 @@ extern int net_is_ipv6_supported();
*/ */
extern const char* net_get_peer_address(int fd); extern const char* net_get_peer_address(int fd);
extern const char* net_get_local_address(int fd);
/** /**
* See man(3) inet_ntop. * See man(3) inet_ntop.
*/ */

216
src/network/select.c Normal file
View File

@@ -0,0 +1,216 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, 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 USE_SELECT
#include "network/connection.h"
#include "network/common.h"
#include "network/backend.h"
struct net_connection_select
{
NET_CON_STRUCT_COMMON
};
struct net_backend
{
size_t num;
size_t max;
struct net_connection_select** conns;
fd_set rfds;
fd_set wfds;
time_t now;
struct timeout_queue timeout_queue;
struct net_cleanup_handler* cleaner;
};
static struct net_backend* g_backend = 0;
static void net_con_print(const char* prefix, struct net_connection_select* con)
{
char buf[512];
int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, events=%s%s",
prefix, con->sd, con->flags, con->callback, con->ptr, (con->flags & NET_EVENT_READ ? "R" : ""),(con->flags & NET_EVENT_WRITE ? "W" : ""));
if (con->timeout)
{
sprintf(buf + off, ", timeout={ %d seconds left }", (int) (con->timeout->timestamp - g_backend->now));
}
else
{
sprintf(buf + off, ", timeout=NULL");
}
LOG_TRACE(buf);
}
/**
* Initialize the network backend.
* Returns 1 on success, or 0 on failure.
*/
int net_backend_initialize()
{
size_t max = net_get_max_sockets();
g_backend = hub_malloc(sizeof(struct net_backend));
g_backend->num = 0;
g_backend->max = max;
g_backend->conns = hub_malloc_zero(sizeof(struct net_connection_select*) * max);
FD_ZERO(&g_backend->rfds);
FD_ZERO(&g_backend->wfds);
g_backend->now = time(0);
timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* look max 10 minutes into the future. */
g_backend->cleaner = net_cleanup_initialize(max);
return 1;
}
/**
* Shutdown the network connection backend.
*/
void net_backend_shutdown()
{
timeout_queue_shutdown(&g_backend->timeout_queue);
net_cleanup_shutdown(g_backend->cleaner);
hub_free(g_backend->conns);
hub_free(g_backend);
}
/**
* Process the network backend.
*/
int net_backend_process()
{
int n, found, maxfd;
struct timeval tval;
FD_ZERO(&g_backend->rfds);
FD_ZERO(&g_backend->wfds);
size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
tval.tv_secs = secs;
tval.tv_usecs = 0;
for (n = 0, found = 0; found < g_backend->num && n < g_backend->max; n++)
{
struct net_connection_select* con = g_backend->conns[n];
if (con)
{
if (con->flags & NET_EVENT_READ) FD_SET(con->sd, &g_backend->rfds);
if (con->flags & NET_EVENT_WRITE) FD_SET(con->sd, &g_backend->wfds);
found++;
maxfd = con->sd;
}
}
int res = select(maxfd+1, &g_backend->rfds, &g_backend->wfds, 0, &tval);
g_backend->now = time(0);
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
if (res == -1)
{
LOG_WARN("select returned -1");
return 0;
}
for (n = 0, found = 0; found < res && n < (maxfd+1); n++)
{
struct net_connection_select* con = g_backend->conns[n];
if (con)
{
int ev = 0;
if (FD_ISSET(con->sd, &g_backend->rfds)) ev |= NET_EVENT_READ;
if (FD_ISSET(con->sd, &g_backend->wfds)) ev |= NET_EVENT_WRITE;
if (ev)
{
net_con_callback((struct net_connection*) con, ev);
found++;
}
}
}
net_cleanup_process(g_backend->cleaner);
return 1;
}
struct timeout_queue* net_backend_get_timeout_queue()
{
return &g_backend->timeout_queue;
}
struct net_connection* net_con_create()
{
struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection_select));
con->sd = -1;
return con;
}
void net_con_destroy(struct net_connection* con)
{
hub_free(con);
}
void net_con_initialize(struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr, int events)
{
struct net_connection_select* con = (struct net_connection_select*) con_;
con->sd = sd;
con->flags = events;
con->callback = callback;
con->ptr = (void*) ptr;
net_set_nonblocking(con->sd, 1);
net_set_nosigpipe(con->sd, 1);
g_backend->conns[sd] = con;
g_backend->num++;
net_con_print("ADD", con);
}
void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events)
{
con->callback = callback;
con->ptr = (void*) ptr;
net_con_update(con, events);
}
void net_con_update(struct net_connection* con, int events)
{
con->flags = events;
net_con_print("MOD", (struct net_connection_select*) con);
}
void net_con_close(struct net_connection* con)
{
if (con->flags & NET_CLEANUP)
return;
if (con->sd != -1)
{
g_backend->conns[con->sd] = 0;
g_backend->num--;
}
net_con_clear_timeout(con);
net_close(con->sd);
con->sd = -1;
net_con_print("DEL", (struct net_connection_select*) con);
net_cleanup_delayed_free(g_backend->cleaner, con);
}
#endif /* USE_SELECT */

50
src/network/timer.c Normal file
View File

@@ -0,0 +1,50 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, 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/connection.h"
static void timeout_callback(struct timeout_evt* evt)
{
net_con_callback((struct net_connection*) evt->ptr, NET_EVENT_TIMEOUT);
}
void net_con_set_timeout(struct net_connection* con, int seconds)
{
if (!con->timeout)
{
con->timeout = hub_malloc_zero(sizeof(struct timeout_evt));
timeout_evt_initialize(con->timeout, timeout_callback, con);
timeout_queue_insert(net_backend_get_timeout_queue(), con->timeout, seconds);
}
else
{
timeout_queue_reschedule(net_backend_get_timeout_queue(), con->timeout, seconds);
}
}
void net_con_clear_timeout(struct net_connection* con)
{
if (con->timeout && timeout_evt_is_scheduled(con->timeout))
{
timeout_queue_remove(net_backend_get_timeout_queue(), con->timeout);
hub_free(con->timeout);
con->timeout = 0;
}
}

View File

@@ -102,13 +102,12 @@
#define uhub_assert assert #define uhub_assert assert
#ifdef USE_LIBEVENT
#include <event.h>
#else
#ifdef __linux__ #ifdef __linux__
#define USE_EPOLL #define USE_EPOLL
#include <sys/epoll.h> #include <sys/epoll.h>
#endif #else
#define USE_SELECT
#include <sys/select.h>
#endif #endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__)

View File

@@ -75,19 +75,13 @@ static void event_callback(struct net_connection* con, int events, void *arg)
{ {
struct ADC_client* client = (struct ADC_client*) net_con_get_ptr(con); struct ADC_client* client = (struct ADC_client*) net_con_get_ptr(con);
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED)
{
printf("NET_EVENT_SOCKERROR || NET_EVENT_CLOSED\n");
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
return;
}
if (events == NET_EVENT_TIMEOUT) if (events == NET_EVENT_TIMEOUT)
{ {
if (client->state == ps_conn) if (client->state == ps_conn)
{ {
client->callback(client, ADC_CLIENT_DISCONNECTED, 0); client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
} }
return;
} }
if (events & NET_EVENT_READ) if (events & NET_EVENT_READ)

View File

@@ -330,7 +330,7 @@ void runloop(size_t clients)
while (running) while (running)
{ {
event_base_loop(net_get_evbase(), EVLOOP_ONCE); net_backend_process();
} }
for (n = 0; n < clients; n++) for (n = 0; n < clients; n++)
@@ -413,63 +413,17 @@ void parse_command_line(int argc, char** argv)
} }
} }
#ifndef WIN32
static void handle_signal(int signal, short events, void* arg)
{
switch (signal)
{
case SIGINT:
case SIGTERM:
running = 0;
break;
default:
break;
}
}
static struct event signal_events[10];
static int signals[] =
{
SIGINT, /* Interrupt the application */
SIGTERM, /* Terminate the application */
0
};
void setup_signal_handlers()
{
int i = 0;
for (i = 0; signals[i]; i++)
{
signal_set(&signal_events[i], signals[i], handle_signal, NULL);
signal_add(&signal_events[i], NULL);
}
}
void shutdown_signal_handlers()
{
int i = 0;
for (i = 0; signals[i]; i++)
{
signal_del(&signal_events[i]);
}
}
#endif /* WIN32 */
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
parse_command_line(argc, argv); parse_command_line(argc, argv);
net_initialize(); net_initialize();
setup_signal_handlers();
hub_log_initialize(NULL, 0); hub_log_initialize(NULL, 0);
hub_set_log_verbosity(1000); hub_set_log_verbosity(1000);
runloop(cfg_clients); runloop(cfg_clients);
shutdown_signal_handlers();
net_destroy(); net_destroy();
return 0; return 0;
} }

View File

@@ -63,6 +63,7 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type,
return 1; return 1;
} }
static int running = 1;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
@@ -79,7 +80,10 @@ int main(int argc, char** argv)
ADC_client_set_callback(&client, handle); ADC_client_set_callback(&client, handle);
ADC_client_connect(&client, argv[1]); ADC_client_connect(&client, argv[1]);
event_dispatch(); while (running)
{
net_backend_process();
}
ADC_client_destroy(&client); ADC_client_destroy(&client);
net_destroy(); net_destroy();

View File

@@ -36,7 +36,6 @@ void timeout_evt_reset(struct timeout_evt* t)
int timeout_evt_is_scheduled(struct timeout_evt* t) int timeout_evt_is_scheduled(struct timeout_evt* t)
{ {
if (!t) return 0;
return !!t->prev; return !!t->prev;
} }
@@ -59,12 +58,11 @@ size_t timeout_queue_process(struct timeout_queue* t, time_t now)
size_t pos; size_t pos;
size_t events = 0; size_t events = 0;
struct timeout_evt* evt = 0; struct timeout_evt* evt = 0;
for (pos = t->last; pos < now; pos++) for (pos = t->last; pos <= now; pos++)
{ {
while ((evt = t->events[pos % t->max])) while ((evt = t->events[pos % t->max]))
{ {
timeout_queue_remove(t, evt); timeout_queue_remove(t, evt);
timeout_evt_reset(evt);
evt->callback(evt); evt->callback(evt);
events++; events++;
} }
@@ -73,6 +71,19 @@ size_t timeout_queue_process(struct timeout_queue* t, time_t now)
return events; return events;
} }
size_t timeout_queue_get_next_timeout(struct timeout_queue* t, time_t now)
{
size_t seconds = 0;
while (t->events[(now + seconds) % t->max] == NULL && seconds < t->max)
{
seconds++;
}
if (seconds == 0)
return 1;
return seconds;
}
void timeout_queue_insert(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds) void timeout_queue_insert(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds)
{ {
struct timeout_evt* first; struct timeout_evt* first;
@@ -82,16 +93,18 @@ void timeout_queue_insert(struct timeout_queue* t, struct timeout_evt* evt, size
first = t->events[pos]; first = t->events[pos];
if (!first) if (first)
{
first->prev->next = evt;
evt->prev = first->prev;
first->prev = evt;
}
else
{ {
t->events[pos] = evt; t->events[pos] = evt;
evt->prev = evt; evt->prev = evt;
} }
else evt->next = 0;
{
evt->prev = first->prev;
first->prev = evt;
}
} }
void timeout_queue_remove(struct timeout_queue* t, struct timeout_evt* evt) void timeout_queue_remove(struct timeout_queue* t, struct timeout_evt* evt)
@@ -99,23 +112,32 @@ void timeout_queue_remove(struct timeout_queue* t, struct timeout_evt* evt)
size_t pos = (evt->timestamp % t->max); size_t pos = (evt->timestamp % t->max);
struct timeout_evt* first = t->events[pos]; struct timeout_evt* first = t->events[pos];
if (!first) if (!first || !evt->prev)
return; return;
if (first == evt) if (first == evt)
{ {
if (first->next) if (first->prev != first)
first->next->prev = first->prev; {
t->events[pos] = first->next; t->events[pos] = first->next;
t->events[pos]->prev = evt->prev;
}
else
{
t->events[pos] = 0;
}
}
else if (evt == first->prev)
{
first->prev = evt->prev;
evt->prev->next = 0;
} }
else else
{ {
evt->prev->next = evt->next; evt->prev->next = evt->next;
if (evt->next)
evt->next->prev = evt->prev; evt->next->prev = evt->prev;
else
first->prev = evt->prev;
} }
timeout_evt_reset(evt);
} }
void timeout_queue_reschedule(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds) void timeout_queue_reschedule(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds)
@@ -124,3 +146,4 @@ void timeout_queue_reschedule(struct timeout_queue* t, struct timeout_evt* evt,
timeout_queue_remove(t, evt); timeout_queue_remove(t, evt);
timeout_queue_insert(t, evt, seconds); timeout_queue_insert(t, evt, seconds);
} }

View File

@@ -53,4 +53,6 @@ void timeout_queue_insert(struct timeout_queue*, struct timeout_evt*, size_t sec
void timeout_queue_remove(struct timeout_queue*, struct timeout_evt*); void timeout_queue_remove(struct timeout_queue*, struct timeout_evt*);
void timeout_queue_reschedule(struct timeout_queue*, struct timeout_evt*, size_t seconds); void timeout_queue_reschedule(struct timeout_queue*, struct timeout_evt*, size_t seconds);
size_t timeout_queue_get_next_timeout(struct timeout_queue*, time_t now);
#endif /* HAVE_UHUB_TIMEOUT_HANDLER_H */ #endif /* HAVE_UHUB_TIMEOUT_HANDLER_H */

16
tools/create_certificate.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
OPENSSL=/usr/bin/openssl
NAME=certificate
if [ ! -x ${OPENSSL} ]; then
echo "Cannot locate the openssl utility: ${OPENSSL}"
exit 1
fi
${OPENSSL} genrsa -out ${NAME}.key 1024 &&
${OPENSSL} req -new -x509 -nodes -sha1 -days 365 -key ${NAME}.key > ${NAME}.crt &&
cat ${NAME}.key ${NAME}.crt > ${NAME}.pem && rm -f ${NAME}.key ${NAME}.crt
echo "Created certificate ${NAME}.pem"

View File

@@ -9,7 +9,7 @@
#endif #endif
#ifndef VERSION #ifndef VERSION
#define VERSION "0.3.0-rc4" REVISION #define VERSION "0.3.0" REVISION
#endif #endif
#ifndef COPYRIGHT #ifndef COPYRIGHT