Compare commits

..

1 Commits

Author SHA1 Message Date
Jan Vidar Krey
f1cd5bb535 Branched off 0.2.x stable branch (0.2.x-stable) 2009-05-29 14:43:41 +02:00
70 changed files with 2819 additions and 3581 deletions

2
.gitignore vendored
View File

@@ -1,2 +0,0 @@
*~
*.o

View File

@@ -1,6 +1,6 @@
##
## Makefile for uhub (Use GNU make)
## Copyright (C) 2007-2009, Jan Vidar Krey <janvidar@extatic.org>
## Copyright (C) 2007-2008, Jan Vidar Krey <janvidar@extatic.org>
#
CC = gcc
@@ -21,9 +21,6 @@ ifeq ($(OS), Windows_NT)
WINDOWS ?= YES
endif
CFLAGS += -I./src/
ifeq ($(WINDOWS),YES)
USE_BIGENDIAN := NO
LDLIBS += -lws2_32
@@ -32,7 +29,6 @@ UHUB_PREFIX ?= c:/uhub/
CFLAGS += -mno-cygwin
LDFLAGS += -mno-cygwin
BIN_EXT ?= .exe
GIT_REVISION ?= NO
else
DESTDIR ?= /
UHUB_CONF_DIR ?= $(DESTDIR)/etc/uhub
@@ -64,15 +60,17 @@ else
MSG_CLEAN="Clean as a whistle"
endif
CFLAGS += -I/source/libevent
LDFLAGS += -L/source/libevent
-include release_setup.mk
ifeq ($(RELEASE),YES)
CFLAGS += -O3 -DNDEBUG
GIT_REVISION ?= NO
CFLAGS += -Os -DNDEBUG
else
CFLAGS += -ggdb -DDEBUG
GIT_REVISION ?= YES
CFLAGS += -g -DDEBUG
endif
ifeq ($(STACK_PROTECT),YES)
@@ -129,68 +127,58 @@ CFLAGS += -I$(LIBEVENT_PATH)
LDFLAGS += -L$(LIBEVENT_PATH)
endif
ifeq ($(GIT_REVISION),YES)
CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\"
endif
# Sources
libuhub_SOURCES := \
src/core/auth.c \
src/core/commands.c \
src/core/config.c \
src/core/eventqueue.c \
src/core/hub.c \
src/core/hubevent.c \
src/core/hubio.c \
src/core/inf.c \
src/util/ipcalc.c \
src/util/list.c \
src/util/log.c \
src/util/memory.c \
src/adc/message.c \
src/util/misc.c \
src/core/netevent.c \
src/network/connection.c \
src/network/network.c \
src/util/rbtree.c \
src/core/route.c \
src/adc/sid.c \
src/util/tiger.c \
src/core/user.c \
src/core/usermanager.c
src/auth.c \
src/commands.c \
src/config.c \
src/eventqueue.c \
src/hubevent.c \
src/hub.c \
src/inf.c \
src/ipcalc.c \
src/list.c \
src/log.c \
src/memory.c \
src/message.c \
src/misc.c \
src/netevent.c \
src/network.c \
src/rbtree.c \
src/route.c \
src/sid.c \
src/tiger.c \
src/user.c \
src/usermanager.c
uhub_SOURCES := src/core/main.c
uhub_SOURCES := src/main.c
adcrush_SOURCES := src/tools/adcrush.c
admin_SOURCES := src/admin.c
adcrush_SOURCES := src/adcrush.c
uhub_HEADERS := \
src/adc/adcconst.h \
src/core/auth.h \
src/core/config.h \
src/core/eventid.h \
src/core/eventqueue.h \
src/core/hub.h \
src/core/hubevent.h \
src/core/hubio.h \
src/core/inf.h \
src/util/ipcalc.h \
src/util/list.h \
src/util/log.h \
src/util/memory.h \
src/adc/message.h \
src/util/misc.h \
src/core/netevent.h \
src/network/connection.h \
src/network/network.h \
src/util/rbtree.h \
src/core/route.h \
src/adc/sid.h \
src/util/tiger.h \
src/adcconst.h \
src/auth.h \
src/config.h \
src/eventid.h \
src/eventqueue.h \
src/hubevent.h \
src/hub.h \
src/inf.h \
src/ipcalc.h \
src/list.h \
src/log.h \
src/memory.h \
src/message.h \
src/misc.h \
src/netevent.h \
src/network.h \
src/rbtree.h \
src/route.h \
src/sid.h \
src/tiger.h \
src/uhub.h \
src/core/user.h \
src/core/usermanager.h
src/user.h \
src/usermanager.h
autotest_SOURCES := \
autotest/test_message.tcc \
@@ -210,46 +198,49 @@ autotest_OBJECTS = autotest.o
libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o)
uhub_OBJECTS := $(uhub_SOURCES:.c=.o)
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o)
admin_OBJECTS := $(admin_SOURCES:.c=.o)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS)
LIBUHUB=libuhub.a
uhub_BINARY=uhub$(BIN_EXT)
adcrush_BINARY=adcrush$(BIN_EXT)
admin_BINARY=uhub-admin$(BIN_EXT)
autotest_BINARY=autotest/test$(BIN_EXT)
%.o: %.c
$(MSG_CC) $(CC) -c $(CFLAGS) -o $@ $^
$(MSG_CC) $(CC) -c $(CFLAGS) -o $@.tmp $^ && \
$(MV) $@.tmp $@
all: $(uhub_BINARY) $(PCH)
$(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
$(admin_BINARY): $(PCH) $(LIBUHUB) $(admin_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
$(MSG_LD) $(CC) -o $@.tmp $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
$(MV) $@.tmp $@
$(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
$(MSG_LD) $(CC) -o $@.tmp $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
$(MV) $@.tmp $@
$(LIBUHUB): $(libuhub_OBJECTS)
$(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@
$(MSG_AR) $(AR) rc $@.tmp $^ && \
$(RANLIB) $@.tmp && \
$(MV) $@.tmp $@
ifeq ($(USE_PCH),YES)
$(PCH): $(uhub_HEADERS)
$(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC)
$(MSG_PCH) $(CC) $(CFLAGS) -o $@.tmp $(PCHSRC) && \
$(MV) $@.tmp $@
endif
autotest.c: $(autotest_SOURCES)
$(shell exotic --standalone $(autotest_SOURCES) > $@)
$(autotest_OBJECTS): autotest.c
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@ $<
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@.tmp $< && \
$(MV) $@.tmp $@
$(autotest_BINARY): $(autotest_OBJECTS) $(LIBUHUB)
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
$(MSG_LD) $(CC) -o $@.tmp $^ $(LDFLAGS) $(LDLIBS) && \
$(MV) $@.tmp $@
autotest: $(autotest_BINARY)
@./$(autotest_BINARY) -s -f
@@ -275,4 +266,5 @@ clean:
@rm -rf $(libuhub_OBJECTS) $(PCH) *~ core $(uhub_BINARY) $(LIBUHUB) $(all_OBJECTS) && \
echo $(MSG_CLEAN)
-include release_targets.mk

View File

@@ -10,8 +10,8 @@ static void create_test_user()
if (g_user)
return;
g_user = (struct hub_user*) malloc(sizeof(struct hub_user));
memset(g_user, 0, sizeof(struct hub_user));
g_user = (struct user*) malloc(sizeof(struct user));
memset(g_user, 0, sizeof(struct user));
memcpy(g_user->id.nick, "exotic-tester", 13);
g_user->sid = 1;
}
@@ -67,5 +67,5 @@ EXO_TEST(hub_service_shutdown, {
});
EXO_TEST(hub_net_shutdown, {
return (net_destroy() != -1);
return (net_shutdown() != -1);
});

View File

@@ -5,17 +5,17 @@
#define USER_NICK "Friend"
#define USER_SID "AAAB"
static struct hub_user* inf_user = 0;
static struct user* inf_user = 0;
static struct hub_info* inf_hub = 0;
extern int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd);
extern int hub_handle_info_login(struct hub_info* hub, struct user* user, struct adc_message* cmd);
static void inf_create_hub()
{
inf_hub = (struct hub_info*) hub_malloc_zero(sizeof(struct hub_info));
inf_hub->users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
inf_hub->users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
inf_hub->users->list = list_create();
inf_hub->users->sids = sid_pool_create(500);
inf_hub->users->free_sid = 1;
inf_hub->acl = (struct acl_handle*) hub_malloc_zero(sizeof(struct acl_handle));
inf_hub->config = (struct hub_config*) hub_malloc_zero(sizeof(struct hub_config));
@@ -28,7 +28,6 @@ static void inf_destroy_hub()
{
/* FIXME */
list_destroy(inf_hub->users->list);
sid_pool_destroy(inf_hub->users->sids);
acl_shutdown(inf_hub->acl);
free_config(inf_hub->config);
hub_free(inf_hub->users);
@@ -41,9 +40,9 @@ static void inf_destroy_hub()
static void inf_create_user()
{
if (inf_user) return;
inf_user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
inf_user = (struct user*) hub_malloc_zero(sizeof(struct user));
inf_user->id.sid = 1;
inf_user->net.connection.sd = -1;
inf_user->sd = -1;
inf_user->limits.upload_slots = 1;
}

View File

@@ -9,8 +9,8 @@ static struct ip_addr_encap ip6_a;
static struct ip_addr_encap ip6_b;
static struct ip_addr_encap ip6_c;
static struct ip_addr_encap mask;
static struct ip_range ban6;
static struct ip_range ban4;
static struct ip_ban_record ban6;
static struct ip_ban_record ban4;
EXO_TEST(prepare_network, {
return net_initialize() == 0;
@@ -405,74 +405,74 @@ EXO_TEST(check_ban_setup_1, {
EXO_TEST(check_ban_ipv4_1, {
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.0", &addr);
return ip_in_range(&addr, &ban4);
return acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_ipv4_2, {
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.1", &addr);
return ip_in_range(&addr, &ban4);
return acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_ipv4_3, {
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.255", &addr);
return ip_in_range(&addr, &ban4);
return acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_ipv4_4, {
struct ip_addr_encap addr; ip_convert_to_binary("192.168.1.0", &addr);
return !ip_in_range(&addr, &ban4);
return !acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_ipv4_5, {
struct ip_addr_encap addr; ip_convert_to_binary("192.167.255.255", &addr);
return !ip_in_range(&addr, &ban4);
return !acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_ipv6_1, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:0", &addr);
return ip_in_range(&addr, &ban6);
return acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_2, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:1", &addr);
return ip_in_range(&addr, &ban6);
return acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_3, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:fffe", &addr);
return ip_in_range(&addr, &ban6);
return acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_4, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefa:ffff", &addr);
return ip_in_range(&addr, &ban6);
return acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_5, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fefb:0", &addr);
return !ip_in_range(&addr, &ban6);
return !acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_ipv6_6, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
return !ip_in_range(&addr, &ban6);
return !acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(check_ban_afmix_1, {
if (!ipv6) return 1;
struct ip_addr_encap addr; ip_convert_to_binary("2001::201:2ff:fef9:ffff", &addr);
return !ip_in_range(&addr, &ban4);
return !acl_check_ip_range(&addr, &ban4);
});
EXO_TEST(check_ban_afmix_2, {
struct ip_addr_encap addr; ip_convert_to_binary("10.20.30.40", &addr);
return !ip_in_range(&addr, &ban6);
return !acl_check_ip_range(&addr, &ban6);
});
EXO_TEST(ip4_bitwise_AND_1, {
@@ -594,28 +594,6 @@ EXO_TEST(ip6_bitwise_OR_3, {
return !strcmp(ip_convert_to_string(&ip6_c), "7777:cccc:3333:1111:ffff:ffff:ffff:1c1c");
});
EXO_TEST(ip_range_1, {
struct ip_range range; memset(&range, 0, sizeof(range));
return ip_convert_address_to_range("192.168.0.1", &range) && memcmp(&range.lo, &range.hi, sizeof(struct ip_addr_encap)) == 0;
});
EXO_TEST(ip_range_2, {
struct ip_range range; memset(&range, 0, sizeof(range));
return ip_convert_address_to_range("192.168.0.0-192.168.255.255", &range) && range.lo.af == range.hi.af && memcmp(&range.lo, &range.hi, sizeof(struct ip_addr_encap)) != 0;
});
EXO_TEST(ip_range_3, {
struct ip_range range; memset(&range, 0, sizeof(range));
return ip_convert_address_to_range("192.168.0.0/16", &range) && range.lo.af == range.hi.af && memcmp(&range.lo, &range.hi, sizeof(struct ip_addr_encap)) != 0;
});
EXO_TEST(ip_range_4, {
struct ip_range range1; memset(&range1, 0, sizeof(range1));
struct ip_range range2; memset(&range2, 0, sizeof(range2));
return ip_convert_address_to_range("192.168.0.0/16", &range1) && ip_convert_address_to_range("192.168.0.0-192.168.255.255", &range2) && memcmp(&range1, &range2, sizeof(struct ip_range)) == 0;
});
EXO_TEST(shutdown_network, {
return net_destroy() == 0;
return net_shutdown() == 0;
});

View File

@@ -1,5 +1,5 @@
#include <uhub.h>
static struct hub_user* g_user = 0;
static struct user* g_user = 0;
static const char* test_string1 = "IINF AAfoo BBbar CCwhat\n";
static const char* test_string2 = "BMSG AAAB Hello\\sWorld!\n";
static const char* test_string3 = "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1 AW\n";
@@ -11,8 +11,8 @@ static void create_test_user()
if (g_user)
return;
g_user = (struct hub_user*) malloc(sizeof(struct hub_user));
memset(g_user, 0, sizeof(struct hub_user));
g_user = (struct user*) malloc(sizeof(struct user));
memset(g_user, 0, sizeof(struct user));
memcpy(g_user->id.nick, "exotic-tester", 13);
g_user->id.sid = 1;
}

View File

@@ -1,105 +0,0 @@
#include <uhub.h>
#define MAX_USERS 64
static struct hub_info um_hub;
static struct hub_user um_user[MAX_USERS];
EXO_TEST(um_test_setup, {
int i = 0;
memset(&um_hub, 0, sizeof(um_hub));
for (i = 0; i < MAX_USERS; i++)
{
memset(&um_user[i], 0, sizeof(struct hub_user));
um_user[i].id.sid = i+1;
um_user[i].net.connection.sd = -1;
}
return 1;
});
EXO_TEST(um_init_1, {
return uman_init(0) != 0;
});
EXO_TEST(um_init_2, {
return uman_init(&um_hub) == 0;
});
EXO_TEST(um_shutdown_1, {
return uman_shutdown(0) == -1;
});
EXO_TEST(um_shutdown_2, {
return uman_shutdown(&um_hub) == 0;
});
EXO_TEST(um_shutdown_3, {
return uman_shutdown(&um_hub) == -1;
});
EXO_TEST(um_init_3, {
return uman_init(&um_hub) == 0;
});
EXO_TEST(um_add_1, {
return uman_add(&um_hub, &um_user[0]) == 0;
});
EXO_TEST(um_size_1, {
return hub_get_user_count(&um_hub) == 1;
});
EXO_TEST(um_remove_1, {
return uman_remove(&um_hub, &um_user[0]) == 0;
});
EXO_TEST(um_size_2, {
return hub_get_user_count(&um_hub) == 0;
});
EXO_TEST(um_add_2, {
int i;
for (i = 0; i < MAX_USERS; i++)
{
if (uman_add(&um_hub, &um_user[i]) != 0)
return 0;
}
return 1;
});
EXO_TEST(um_size_3, {
return hub_get_user_count(&um_hub) == MAX_USERS;
});
EXO_TEST(um_add_3, {
return uman_add(&um_hub, &um_user[5]) != 0;
});
EXO_TEST(um_remove_2, {
int i;
for (i = 0; i < MAX_USERS; i++)
{
if (uman_remove(&um_hub, &um_user[i]) != 0)
return 0;
}
return 1;
});
/* Last test */
EXO_TEST(um_shutdown_4, {
return uman_shutdown(&um_hub) == 0;
});

View File

@@ -12,8 +12,8 @@
# 'ban_cid' - banned user by cid
# Administrator
# user_admin userA:password1
# user_op userB:password2
user_admin Dj_Offset:uhub
user_op janvidar:password
# We don't want users with these names
deny_nick Hub-Security

View File

@@ -1,130 +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/>.
*
*/
#include "uhub.h"
const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
char* sid_to_string(sid_t sid_)
{
static char t_sid[5];
sid_t sid = (sid_ & 0xFFFFF); /* 20 bits only */
sid_t A, B, C, D = 0;
D = (sid % 32);
sid = (sid - D) / 32;
C = (sid % 32);
sid = (sid - C) / 32;
B = (sid % 32);
sid = (sid - B) / 32;
A = (sid % 32);
t_sid[0] = BASE32_ALPHABET[A];
t_sid[1] = BASE32_ALPHABET[B];
t_sid[2] = BASE32_ALPHABET[C];
t_sid[3] = BASE32_ALPHABET[D];
t_sid[4] = 0;
return t_sid;
}
sid_t string_to_sid(const char* sid)
{
sid_t nsid = 0;
sid_t n, x;
sid_t factors[] = { 32768, 1024, 32, 1};
if (!sid || strlen(sid) != 4) return 0;
for (n = 0; n < 4; n++) {
for (x = 0; x < strlen(BASE32_ALPHABET); x++)
if (sid[n] == BASE32_ALPHABET[x]) break;
if (x == 32) return 0;
nsid += x * factors[n];
}
return nsid;
}
/*
* Session IDs are heavily reused, since they are a fairly scarce
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
* value and 'AAAA' (0) is reserved for the hub.
*
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
*
* When allocating a session ID:
* - If 'count' is less than the pool size (max-min), then allocate within the pool
* - Increase the pool size (see below)
* - If unable to do that, hub is really full - don't let anyone in!
*
* When freeing a session ID:
* - If the session ID being freed is 'max', then decrease the pool size by one.
*
*/
struct sid_pool
{
sid_t min;
sid_t max;
sid_t count;
struct hub_user** map;
};
struct sid_pool* sid_pool_create(sid_t max)
{
struct sid_pool* pool = hub_malloc(sizeof(struct sid_pool));
pool->min = 1;
pool->max = max + 1;
pool->count = 0;
pool->map = hub_malloc_zero(sizeof(struct hub_user*) * pool->max);
pool->map[0] = (struct hub_user*) pool; /* hack to reserve the first sid. */
LOG_DUMP("SID_POOL: max=%d", (int) pool->max);
return pool;
}
void sid_pool_destroy(struct sid_pool* pool)
{
LOG_DUMP("SID_POOL: destroying, current allocs=%d", (int) pool->count);
hub_free(pool->map);
hub_free(pool);
}
sid_t sid_alloc(struct sid_pool* pool, struct hub_user* user)
{
sid_t n = (++pool->count);
for (; (pool->map[n % pool->max]); n++) ;
LOG_DUMP("SID_ALLOC: %d, user=%p", (int) n, user);
pool->map[n] = user;
return n;
}
void sid_free(struct sid_pool* pool, sid_t sid)
{
LOG_DUMP("SID_FREE: %d", (int) sid);
pool->map[sid] = 0;
pool->count--;
}
struct hub_user* sid_lookup(struct sid_pool* pool, sid_t sid)
{
if (!sid || (sid > pool->max))
return 0;
return pool->map[sid];
}

View File

@@ -386,7 +386,7 @@ static int recv_client(struct ADC_client* client)
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
char* lastPos;
while ((pos = strchr(start, '\n')))
{
lastPos = pos;
@@ -482,16 +482,9 @@ static int recv_client(struct ADC_client* client)
start = &pos[1];
}
if (lastPos)
{
client->r_offset = strlen(lastPos);
memmove(client->recvbuf, lastPos, strlen(lastPos));
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
}
else
{
// client->r_offset = size;
}
client->r_offset = strlen(lastPos);
memmove(client->recvbuf, lastPos, strlen(lastPos));
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
return 0;
@@ -951,7 +944,7 @@ int main(int argc, char** argv)
net_string_to_address(AF_INET, cfg_host, &saddr.sin_addr);
runloop(cfg_clients);
net_destroy();
net_shutdown();
return 0;
}

View File

@@ -55,12 +55,12 @@ static int check_cmd_bool(const char* cmd, struct linked_list* list, char* line,
data = strip_white_space(data);
if (!*data)
{
LOG_FATAL("ACL parse error on line %d", line_count);
hub_log(log_fatal, "ACL parse error on line %d", line_count);
return -1;
}
list_append(list, hub_strdup(data));
LOG_DEBUG("ACL: Deny access for: '%s' (%s)", data, cmd);
hub_log(log_debug, "ACL: Deny access for: '%s' (%s)", data, cmd);
return 1;
}
return 0;
@@ -70,7 +70,7 @@ static int check_cmd_user(const char* cmd, int status, struct linked_list* list,
{
char* data;
char* data_extra;
struct hub_user_access_info* info = 0;
struct user_access_info* info = 0;
if (!strncmp(line, cmd, strlen(cmd)))
{
@@ -82,15 +82,15 @@ static int check_cmd_user(const char* cmd, int status, struct linked_list* list,
data = strip_white_space(data);
if (!*data)
{
LOG_FATAL("ACL parse error on line %d", line_count);
hub_log(log_fatal, "ACL parse error on line %d", line_count);
return -1;
}
info = hub_malloc_zero(sizeof(struct hub_user_access_info));
info = hub_malloc_zero(sizeof(struct user_access_info));
if (!info)
{
LOG_ERROR("ACL parse error. Out of memory!");
hub_log(log_error, "ACL parse error. Out of memory!");
return -1;
}
@@ -108,14 +108,14 @@ static int check_cmd_user(const char* cmd, int status, struct linked_list* list,
info->password = data_extra ? hub_strdup(data_extra) : 0;
info->status = status;
list_append(list, info);
LOG_DEBUG("ACL: Added user '%s' (%s)", info->username, get_user_credential_string(info->status));
hub_log(log_debug, "ACL: Added user '%s' (%s)", info->username, get_user_credential_string(info->status));
return 1;
}
return 0;
}
static void add_ip_range(struct linked_list* list, struct ip_range* info)
static void add_ip_range(struct linked_list* list, struct ip_ban_record* info)
{
char buf1[INET6_ADDRSTRLEN+1];
char buf2[INET6_ADDRSTRLEN+1];
@@ -130,44 +130,125 @@ static void add_ip_range(struct linked_list* list, struct ip_range* info)
net_address_to_string(AF_INET6, &info->lo.internal_ip_data.in6, buf1, INET6_ADDRSTRLEN);
net_address_to_string(AF_INET6, &info->hi.internal_ip_data.in6, buf2, INET6_ADDRSTRLEN);
}
LOG_DEBUG("ACL: Deny access for: %s-%s", buf1, buf2);
hub_log(log_debug, "ACL: Deny access for: %s-%s", buf1, buf2);
list_append(list, info);
}
static int check_ip_range(const char* lo, const char* hi, struct ip_ban_record* info)
{
int ret1, ret2;
if ((ip_is_valid_ipv4(lo) && ip_is_valid_ipv4(hi)) ||
(ip_is_valid_ipv6(lo) && ip_is_valid_ipv6(hi)))
{
ret1 = ip_convert_to_binary(lo, &info->lo);
ret2 = ip_convert_to_binary(hi, &info->hi);
if (ret1 == -1 || ret2 == -1 || ret1 != ret2)
{
return -1;
}
return 0;
}
return -1;
}
static int check_ip_mask(const char* text_addr, int bits, struct ip_ban_record* info)
{
hub_log(log_debug, "ACL: Deny access for: %s/%d", text_addr, bits);
if (ip_is_valid_ipv4(text_addr) ||
ip_is_valid_ipv6(text_addr))
{
struct ip_addr_encap addr;
struct ip_addr_encap mask1;
struct ip_addr_encap mask2;
int af = ip_convert_to_binary(text_addr, &addr); /* 192.168.1.2 */
int maxbits = af == AF_INET6 ? 128 : 32;
ip_mask_create_left(af, bits, &mask1); /* 255.255.255.0 */
ip_mask_create_right(af, maxbits - bits, &mask2); /* 0.0.0.255 */
ip_mask_apply_AND(&addr, &mask1, &info->lo); /* 192.168.1.0 */
ip_mask_apply_OR(&info->lo, &mask2, &info->hi); /* 192.168.1.255 */
return 0;
}
return -1;
}
static int check_cmd_addr(const char* cmd, struct linked_list* list, char* line, int line_count)
{
char* data;
struct ip_range* range = 0;
char* data1;
char* data2;
struct ip_ban_record* info = 0;
int cidr_bits = 0;
if (!strncmp(line, cmd, strlen(cmd)))
{
data = &line[strlen(cmd)];
data[0] = '\0';
data++;
data1 = &line[strlen(cmd)];
data2 = 0;
data1[0] = '\0';
data1++;
data = strip_white_space(data);
if (!*data)
data1 = strip_white_space(data1);
if (!*data1)
{
LOG_FATAL("ACL parse error on line %d", line_count);
hub_log(log_fatal, "ACL parse error on line %d", line_count);
return -1;
}
range = hub_malloc_zero(sizeof(struct ip_range));
info = hub_malloc_zero(sizeof(struct ip_ban_record));
if (!range)
if (!info)
{
LOG_ERROR("ACL parse error. Out of memory!");
hub_log(log_error, "ACL parse error. Out of memory!");
return -1;
}
if (ip_convert_address_to_range(data, range))
/* Extract IP-range */
data2 = strrchr(data1, '-');
if (data2)
{
add_ip_range(list, range);
cidr_bits = -1;
data2[0] = 0;
data2++;
if (check_ip_range(data1, data2, info) == -1)
{
hub_free(info);
return 0;
}
add_ip_range(list, info);
return 1;
}
else
{
/* Extract IP-bitmask */
data2 = strrchr(data1, '/');
if (data2)
{
data2[0] = 0;
data2++;
cidr_bits = uhub_atoi(data2);
}
else
{
cidr_bits = 128;
}
if (check_ip_mask(data1, cidr_bits, info) == -1)
{
hub_free(info);
return 0;
}
add_ip_range(list, info);
return 1;
}
hub_free(range);
}
return 0;
}
@@ -188,16 +269,20 @@ static int acl_parse_line(char* line, int line_count, void* ptr_data)
if (!*line)
return 0;
LOG_DEBUG("acl_parse_line(): '%s'", line);
#ifdef ACL_DEBUG
hub_log(log_trace, "acl_parse_line(): '%s'", line);
#endif
line = strip_white_space(line);
if (!*line)
{
LOG_FATAL("ACL parse error on line %d", line_count);
hub_log(log_fatal, "ACL parse error on line %d", line_count);
return -1;
}
LOG_DEBUG("acl_parse_line: '%s'", line);
#ifdef ACL_DEBUG
hub_log(log_trace, "acl_parse_line: '%s'", line);
#endif
ACL_ADD_USER("bot", handle->users, cred_bot);
ACL_ADD_USER("user_admin", handle->users, cred_admin);
@@ -211,7 +296,7 @@ static int acl_parse_line(char* line, int line_count, void* ptr_data)
ACL_ADD_ADDR("deny_ip", handle->networks);
ACL_ADD_ADDR("nat_ip", handle->nat_override);
LOG_ERROR("Unknown ACL command on line %d: '%s'", line_count, line);
hub_log(log_error, "Unknown ACL command on line %d: '%s'", line_count, line);
return -1;
}
@@ -230,7 +315,7 @@ int acl_initialize(struct hub_config* config, struct acl_handle* handle)
if (!handle->users || !handle->cids || !handle->networks || !handle->users_denied || !handle->users_banned || !handle->nat_override)
{
LOG_FATAL("acl_initialize: Out of memory");
hub_log(log_fatal, "acl_initialize: Out of memory");
list_destroy(handle->users);
list_destroy(handle->users_denied);
@@ -255,7 +340,7 @@ int acl_initialize(struct hub_config* config, struct acl_handle* handle)
static void acl_free_access_info(void* ptr)
{
struct hub_user_access_info* info = (struct hub_user_access_info*) ptr;
struct user_access_info* info = (struct user_access_info*) ptr;
if (info)
{
hub_free(info->username);
@@ -319,16 +404,16 @@ int acl_shutdown(struct acl_handle* handle)
}
struct hub_user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name)
struct user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name)
{
struct hub_user_access_info* info = (struct hub_user_access_info*) list_get_first(handle->users);
struct user_access_info* info = (struct user_access_info*) list_get_first(handle->users);
while (info)
{
if (strcasecmp(info->username, name) == 0)
{
return info;
}
info = (struct hub_user_access_info*) list_get_next(handle->users);
info = (struct user_access_info*) list_get_next(handle->users);
}
return NULL;
}
@@ -361,54 +446,19 @@ int acl_is_user_denied(struct acl_handle* handle, const char* data)
STR_LIST_CONTAINS(handle->users_denied, data);
}
int acl_user_ban_nick(struct acl_handle* handle, const char* nick)
{
struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info));
if (!info)
{
LOG_ERROR("ACL error: Out of memory!");
return -1;
}
list_append(handle->users_banned, hub_strdup(nick));
return 0;
}
int acl_user_ban_cid(struct acl_handle* handle, const char* cid)
{
struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info));
if (!info)
{
LOG_ERROR("ACL error: Out of memory!");
return -1;
}
list_append(handle->cids, hub_strdup(cid));
return 0;
}
int acl_user_unban_nick(struct acl_handle* handle, const char* nick)
{
return -1;
}
int acl_user_unban_cid(struct acl_handle* handle, const char* cid)
{
return -1;
}
int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address)
{
struct ip_addr_encap raw;
struct ip_range* info = (struct ip_range*) list_get_first(handle->networks);
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->networks);
ip_convert_to_binary(ip_address, &raw);
while (info)
{
if (ip_in_range(&raw, info))
if (acl_check_ip_range(&raw, info))
{
return 1;
}
info = (struct ip_range*) list_get_next(handle->networks);
info = (struct ip_ban_record*) list_get_next(handle->networks);
}
return 0;
}
@@ -416,62 +466,71 @@ int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address)
int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address)
{
struct ip_addr_encap raw;
struct ip_range* info = (struct ip_range*) list_get_first(handle->nat_override);
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->nat_override);
ip_convert_to_binary(ip_address, &raw);
while (info)
{
if (ip_in_range(&raw, info))
if (acl_check_ip_range(&raw, info))
{
return 1;
}
info = (struct ip_range*) list_get_next(handle->nat_override);
info = (struct ip_ban_record*) list_get_next(handle->nat_override);
}
return 0;
}
int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info)
{
return (addr->af == info->lo.af && ip_compare(&info->lo, addr) <= 0 && ip_compare(addr, &info->hi) <= 0);
}
/*
* This will generate the same challenge to the same user, always.
* The challenge is made up of the time of the user connected
* seconds since the unix epoch (modulus 1 million)
* and the SID of the user (0-1 million).
*/
const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user)
const char* password_generate_challenge(struct user* user)
{
char buf[32];
uint64_t tiger_res[3];
static char tiger_buf[MAX_CID_LEN+1];
snprintf(buf, 32, "%d%d%d", (int) user->net.tm_connected, (int) user->id.sid, (int) user->net.connection.sd);
snprintf(buf, 32, "%d%d%d", (int) user->tm_connected, (int) user->id.sid, (int) user->sd);
tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res);
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
tiger_buf[MAX_CID_LEN] = 0;
#ifdef ACL_DEBUG
hub_log(log_trace, "Generating challenge for user %s: '%s'", user->id.nick, tiger_buf);
#endif
return (const char*) tiger_buf;
}
int acl_password_verify(struct acl_handle* acl, struct hub_user* user, const char* password)
int password_verify(struct user* user, const char* password)
{
char buf[1024];
struct hub_user_access_info* access;
struct user_access_info* access;
const char* challenge;
char raw_challenge[64];
char password_calc[64];
uint64_t tiger_res[3];
if (!password || !user || strlen(password) != MAX_CID_LEN)
return 0;
return password_invalid;
access = acl_get_access_info(acl, user->id.nick);
access = acl_get_access_info(user->hub->acl, user->id.nick);
if (!access || !access->password)
return 0;
return password_invalid;
if (TIGERSIZE+strlen(access->password) >= 1024)
return 0;
return password_invalid;
challenge = acl_password_generate_challenge(acl, user);
challenge = password_generate_challenge(user);
base32_decode(challenge, (unsigned char*) raw_challenge, MAX_CID_LEN);
@@ -482,11 +541,14 @@ int acl_password_verify(struct acl_handle* acl, struct hub_user* user, const cha
base32_encode((unsigned char*) tiger_res, TIGERSIZE, password_calc);
password_calc[MAX_CID_LEN] = 0;
#ifdef ACL_DEBUG
hub_log(log_trace, "Checking password %s against %s", password, password_calc);
#endif
if (strcasecmp(password, password_calc) == 0)
{
return 1;
return password_ok;
}
return 0;
return password_invalid;
}

View File

@@ -21,9 +21,21 @@
#define HAVE_UHUB_ACL_H
struct hub_config;
struct hub_user;
struct user;
struct ip_addr_encap;
enum password_status
{
password_invalid = 0,
password_ok = 1,
};
enum acl_status
{
acl_not_found = 0,
acl_found = 1,
};
enum user_credentials
{
cred_none, /**<<< "User has no credentials (not yet logged in)" */
@@ -38,13 +50,19 @@ enum user_credentials
const char* get_user_credential_string(enum user_credentials cred);
struct hub_user_access_info
struct user_access_info
{
char* username; /* name of user, cid or IP range */
char* password; /* password */
enum user_credentials status;
};
struct ip_ban_record
{
struct ip_addr_encap lo;
struct ip_addr_encap hi;
};
struct acl_handle
{
struct linked_list* users; /* Known users. See enum user_status */
@@ -59,7 +77,7 @@ struct acl_handle
extern int acl_initialize(struct hub_config* config, struct acl_handle* handle);
extern int acl_shutdown(struct acl_handle* handle);
extern struct hub_user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name);
extern struct user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name);
extern int acl_is_cid_banned(struct acl_handle* handle, const char* cid);
extern int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address);
extern int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address);
@@ -67,19 +85,9 @@ extern int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_addr
extern int acl_is_user_banned(struct acl_handle* handle, const char* name);
extern int acl_is_user_denied(struct acl_handle* handle, const char* name);
extern int acl_user_ban_nick(struct acl_handle* handle, const char* nick);
extern int acl_user_ban_cid(struct acl_handle* handle, const char* cid);
extern int acl_user_unban_nick(struct acl_handle* handle, const char* nick);
extern int acl_user_unban_cid(struct acl_handle* handle, const char* cid);
extern int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info);
extern const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user);
/**
* Verify a password.
*
* @param password the hashed password (based on the nonce).
* @return 1 if the password matches, or 0 if the password is incorrect.
*/
extern int acl_password_verify(struct acl_handle* acl, struct hub_user* user, const char* password);
extern const char* password_generate_challenge(struct user* user);
extern int password_verify(struct user* user, const char* password);
#endif /* HAVE_UHUB_ACL_H */

218
src/commands.c Normal file
View File

@@ -0,0 +1,218 @@
/*
* 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/>.
*
*/
#include "uhub.h"
typedef int (*command_handler)(struct hub_info* hub, struct user* user, const char* message);
struct commands_handler
{
const char* prefix;
size_t length;
enum user_credentials cred;
command_handler handler;
const char* description;
};
static struct commands_handler command_handlers[];
static void send_message(struct hub_info* hub, struct user* user, const char* message)
{
char* buffer = adc_msg_escape(message);
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
adc_msg_add_argument(command, buffer);
route_to_user(user, command);
adc_msg_free(command);
hub_free(buffer);
}
static int command_access_denied(struct hub_info* hub, struct user* user, const char* command)
{
char temp[128];
snprintf(temp, 128, "*** Access denied: \"%s\"", command);
send_message(hub, user, temp);
return 0;
}
static int command_not_found(struct hub_info* hub, struct user* user, const char* command)
{
char temp[128];
snprintf(temp, 128, "*** Command not found: \"%s\"", command);
send_message(hub, user, temp);
return 0;
}
static int command_status(struct hub_info* hub, struct user* user, const char* command, const char* message)
{
char temp[1024];
snprintf(temp, 1024, "*** %s: %s", command, message);
send_message(hub, user, temp);
return 0;
}
static int command_stats(struct hub_info* hub, struct user* user, const char* message)
{
char temp[128];
snprintf(temp, 128, "%zu users, peak: %zu. 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(hub, user, "stats", message);
}
static int command_help(struct hub_info* hub, struct user* user, const char* message)
{
#define MAX_HELP_MSG 1024
size_t n;
char msg[MAX_HELP_MSG];
msg[0] = 0;
strcat(msg, "Available commands:\n");
for (n = 0; command_handlers[n].prefix; n++)
{
if (command_handlers[n].cred <= user->credentials)
{
strcat(msg, "!");
strcat(msg, command_handlers[n].prefix);
strcat(msg, " - ");
strcat(msg, command_handlers[n].description);
strcat(msg, "\n");
}
}
return command_status(hub, user, "help", msg);
}
static int command_uptime(struct hub_info* hub, struct user* user, const char* message)
{
char tmp[128];
size_t d;
size_t h;
size_t m;
size_t D = (size_t) difftime(time(0), hub->tm_started);
d = D / (24 * 3600);
D = D % (24 * 3600);
h = D / 3600;
D = D % 3600;
m = D / 60;
tmp[0] = 0;
if (d)
{
strcat(tmp, uhub_itoa((int) d));
strcat(tmp, " day");
if (d != 1) strcat(tmp, "s");
strcat(tmp, ", ");
}
if (h < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) h));
strcat(tmp, ":");
if (m < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) m));
return command_status(hub, user, "uptime", tmp);
}
static int command_kick(struct hub_info* hub, struct user* user, const char* message)
{
if (strlen(message) < 7)
{
return command_status(hub, user, "kick", "No nickname given");
}
const char* nick = &message[7];
struct user* target = uman_get_user_by_nick(hub, nick);
if (!target)
{
return command_status(hub, user, "kick", "No such user");
}
if (target == user)
{
return command_status(hub, user, "kick", "Cannot kick yourself");
}
user_disconnect(target, quit_kicked);
return command_status(hub, user, "kick", nick);
}
static int command_reload(struct hub_info* hub, struct user* user, const char* message)
{
hub->status = hub_status_restart;
return command_status(hub, user, "reload", "Reloading configuration...");
}
static int command_shutdown(struct hub_info* hub, struct user* user, const char* message)
{
hub->status = hub_status_shutdown;
return command_status(hub, user, "shutdown", "Hub shutting down...");
}
static int command_version(struct hub_info* hub, struct user* user, const char* message)
{
return command_status(hub, user, "version", "Powered by " PRODUCT "/" VERSION);
}
static int command_myip(struct hub_info* hub, struct user* user, const char* message)
{
char tmp[128];
snprintf(tmp, 128, "Your IP is \"%s\"", ip_convert_to_string(&user->ipaddr));
return command_status(hub, user, "myip", tmp);
}
int command_dipatcher(struct hub_info* hub, struct user* user, const char* message)
{
size_t n = 0;
for (n = 0; command_handlers[n].prefix; n++)
{
if (!strncmp(message, command_handlers[n].prefix, command_handlers[n].length))
{
if (command_handlers[n].cred <= user->credentials)
{
return command_handlers[n].handler(hub, user, message);
}
else
{
return command_access_denied(hub, user, command_handlers[n].prefix);
}
}
}
command_not_found(hub, user, message);
return 1;
}
static struct commands_handler command_handlers[] = {
{ "help", 4, cred_guest, command_help, "Show this help message." },
{ "stats", 5, cred_super, command_stats, "Show hub statistics." },
{ "version", 7, cred_guest, command_version, "Show hub version info." },
{ "uptime", 6, cred_guest, command_uptime, "Display hub uptime info." },
{ "kick", 4, cred_operator, command_kick, "Kick a user" },
{ "reload", 6, cred_admin, command_reload, "Reload configuration files." },
{ "shutdown", 8, cred_admin, command_shutdown, "Shutdown hub." },
{ "myip", 4, cred_guest, command_myip, "Show your own IP." },
{ 0, 0, cred_none, command_help, "" }
};

View File

@@ -19,4 +19,17 @@
#include "uhub.h"
extern int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message);
#define CHAT_MSG_HANDLED 1
#define CHAT_MSG_IGNORED 0
#define CHAT_MSG_INVALID -1
typedef int (*plugin_event_chat_message)(struct hub_info*, struct user*, struct adc_message*);
struct command_info
{
const char* prefix;
enum user_credentials cred;
plugin_event_chat_message function;
};
int command_dipatcher(struct hub_info* hub, struct user* user, const char* message);

View File

@@ -42,7 +42,7 @@
else if (strncasecmp(data, "off", 3) == 0) TARGET = 0; \
else\
{ \
LOG_FATAL("Configuration error on line %d: '%s' must be either '1' or '0'", line_count, key); \
hub_log(log_fatal, "Configuration error on line %d: '%s' must be either '1' or '0'", line_count, key); \
return -1; \
} \
TARGET |= 0x80000000; \
@@ -65,7 +65,7 @@
errno = 0; \
val = strtol(data, &endptr, 10); \
if (((errno == ERANGE && (val == INT_MAX || val == INT_MIN)) || (errno != 0 && val == 0)) || endptr == data) { \
LOG_FATAL("Configuration error on line %d: '%s' must be a number", line_count, key); \
hub_log(log_fatal, "Configuration error on line %d: '%s' must be a number", line_count, key); \
return -1; \
} \
TARGET = val; \
@@ -103,7 +103,7 @@
#define IGNORED(NAME) \
if (strcmp(#NAME, key) == 0) \
{ \
LOG_WARN("Configuration option %s deprecated and ingnored.", key); \
hub_log(log_warning, "Configuration option %s deprecated and ingnored.", key); \
return 0; \
} \
@@ -116,8 +116,6 @@
#define DEF_FILE_ACL ""
#define DEF_FILE_MOTD ""
#define DEF_MAX_USERS 500
#define DEF_MAX_CHAT_HISTORY 20
#define DEF_MAX_LOGOUT_LOG 100
#define DEF_MAX_RECV_BUFFER 4096
#define DEF_MAX_SEND_BUFFER 131072
#define DEF_MAX_SEND_BUFFER_SOFT 98304
@@ -177,8 +175,6 @@ void config_defaults(struct hub_config* config)
DEFAULT_STRING (file_motd, DEF_FILE_MOTD);
DEFAULT_INTEGER(server_port, DEF_SERVER_PORT);
DEFAULT_INTEGER(max_users, DEF_MAX_USERS);
DEFAULT_INTEGER(max_chat_history, DEF_MAX_CHAT_HISTORY);
DEFAULT_INTEGER(max_logout_log, DEF_MAX_LOGOUT_LOG);
DEFAULT_INTEGER(max_recv_buffer, DEF_MAX_RECV_BUFFER);
DEFAULT_INTEGER(max_send_buffer, DEF_MAX_SEND_BUFFER);
DEFAULT_INTEGER(max_send_buffer_soft, DEF_MAX_SEND_BUFFER_SOFT);
@@ -249,8 +245,6 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
GET_STR (hub_description);
GET_BOOL(hub_enabled);
GET_INT (max_users);
GET_INT (max_chat_history);
GET_INT (max_logout_log);
GET_INT (max_recv_buffer);
GET_INT (max_send_buffer);
GET_INT (max_send_buffer_soft);
@@ -310,7 +304,7 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
GET_STR (tls_private_key);
/* Still here -- unknown directive */
LOG_ERROR("Unknown configuration directive: '%s'", key);
hub_log(log_fatal, "Unknown configuration directive: '%s'", key);
return -1;
}
@@ -397,8 +391,6 @@ void dump_config(struct hub_config* config, int ignore_defaults)
DUMP_STR (hub_description, DEF_HUB_DESCRIPTION);
DUMP_BOOL(hub_enabled, DEF_HUB_ENABLED);
DUMP_INT (max_users, DEF_MAX_USERS);
DUMP_INT (max_chat_history, DEF_MAX_CHAT_HISTORY);
DUMP_INT (max_logout_log, DEF_MAX_LOGOUT_LOG);
DUMP_INT (max_recv_buffer, DEF_MAX_RECV_BUFFER);
DUMP_INT (max_send_buffer, DEF_MAX_SEND_BUFFER);
DUMP_INT (max_send_buffer_soft, DEF_MAX_SEND_BUFFER_SOFT);
@@ -468,11 +460,13 @@ static int config_parse_line(char* line, int line_count, void* ptr_data)
if (!*line) return 0;
LOG_DUMP("config_parse_line(): '%s'", line);
#ifdef CONFIG_DUMP
hub_log(log_trace, "config_parse_line(): '%s'", line);
#endif
if (!is_valid_utf8(line))
{
LOG_WARN("Invalid utf-8 characters on line %d", line_count);
hub_log(log_warning, "Invalid utf-8 characters on line %d", line_count);
}
if ((pos = strchr(line, '=')) != NULL)
@@ -492,11 +486,13 @@ static int config_parse_line(char* line, int line_count, void* ptr_data)
if (!*key || !*data)
{
LOG_FATAL("Configuration parse error on line %d", line_count);
hub_log(log_fatal, "Configuration parse error on line %d", line_count);
return -1;
}
LOG_DUMP("config_parse_line: '%s' => '%s'", key, data);
#ifdef CONFIG_DUMP
hub_log(log_trace, "config_parse_line: '%s' => '%s'", key, data);
#endif
return apply_config(config, key, data, line_count);
}
@@ -513,7 +509,7 @@ int read_config(const char* file, struct hub_config* config, int allow_missing)
{
if (allow_missing && ret == -2)
{
LOG_DUMP("Using default configuration.");
hub_log(log_debug, "Using default configuration.");
}
else
{

View File

@@ -39,9 +39,6 @@ struct hub_config
int max_send_buffer_soft; /**<<< "Max send buffer before message drops, per user (default: 96K)" */
int low_bandwidth_mode; /**<<< "If this is enabled, the hub will strip off elements from each user's info message to reduce bandwidth usage" */
int max_chat_history; /**<<< "Number of chat messages kept in history (default: 20)" */
int max_logout_log; /**<<< "Number of log entries for people leaving the hub. (default: 100) */
/* Limits enforced on users */
int limit_max_hubs_user; /**<<< "Max concurrent hubs as a user. (0=off, default: 10)" */
int limit_max_hubs_reg; /**<<< "Max concurrent hubs as registered user. (0=off, default: 10)" */

View File

@@ -1,551 +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/>.
*
*/
#include "uhub.h"
#ifdef DEBUG
#define CRASH_DEBUG
#endif
#define MAX_HELP_MSG 1024
struct hub_command
{
const char* message;
char* prefix;
size_t prefix_len;
struct linked_list* args;
};
typedef int (*command_handler)(struct hub_info* hub, struct hub_user* user, struct hub_command*);
struct commands_handler
{
const char* prefix;
size_t length;
const char* args;
enum user_credentials cred;
command_handler handler;
const char* description;
};
static struct commands_handler command_handlers[];
static void command_destroy(struct hub_command* cmd)
{
if (!cmd) return;
hub_free(cmd->prefix);
if (cmd->args)
{
list_clear(cmd->args, &hub_free);
list_destroy(cmd->args);
}
hub_free(cmd);
}
static struct hub_command* command_create(const char* message)
{
struct hub_command* cmd = hub_malloc_zero(sizeof(struct hub_command));
if (!cmd) return 0;
cmd->message = message;
cmd->args = list_create();
int n = split_string(message, "\\s", cmd->args, 0);
if (n <= 0)
{
command_destroy(cmd);
return 0;
}
char* prefix = list_get_first(cmd->args);
if (prefix[0] && prefix[1])
{
cmd->prefix = hub_strdup(&prefix[1]);
cmd->prefix_len = strlen(cmd->prefix);
}
else
{
command_destroy(cmd);
return 0;
}
list_remove(cmd->args, prefix);
hub_free(prefix);
return cmd;
}
static void send_message(struct hub_info* hub, struct hub_user* user, const char* message)
{
char* buffer = adc_msg_escape(message);
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
adc_msg_add_argument(command, buffer);
route_to_user(hub, user, command);
adc_msg_free(command);
hub_free(buffer);
}
static int command_access_denied(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "*** %s: Access denied.", cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "*** %s: Command not found", cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_status_user_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* nick)
{
char temp[128];
snprintf(temp, 128, "*** %s: No user \"%s\"", cmd->prefix, nick);
send_message(hub, user, temp);
return 0;
}
const char* command_get_syntax(struct commands_handler* handler)
{
static char args[128];
args[0] = 0;
size_t n = 0;
if (handler->args)
{
for (n = 0; n < strlen(handler->args); n++)
{
if (n > 0) strcat(args, " ");
switch (handler->args[n])
{
case 'n': strcat(args, "<nick>"); break;
case 'c': strcat(args, "<cid>"); break;
case 'a': strcat(args, "<addr>"); break;
case 'm': strcat(args, "<message>"); break;
}
}
}
return args;
}
static int command_arg_mismatch(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, struct commands_handler* handler)
{
char temp[256];
const char* args = command_get_syntax(handler);
if (args) snprintf(temp, 256, "*** %s: Use: !%s %s", cmd->prefix, cmd->prefix, args);
else snprintf(temp, 256, "*** %s: Use: !%s", cmd->prefix, cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_status(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* message)
{
char temp[1024];
snprintf(temp, 1024, "*** %s: %s", cmd->prefix, message);
send_message(hub, user, temp);
return 0;
}
static int command_stats(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "%zu users, peak: %zu. 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(hub, user, cmd, temp);
}
static int command_help(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
size_t n;
char msg[MAX_HELP_MSG];
msg[0] = 0;
strcat(msg, "Available commands:\n");
for (n = 0; command_handlers[n].prefix; n++)
{
if (command_handlers[n].cred <= user->credentials)
{
strcat(msg, "!");
strcat(msg, command_handlers[n].prefix);
strcat(msg, " - ");
strcat(msg, command_handlers[n].description);
strcat(msg, "\n");
}
}
return command_status(hub, user, cmd, msg);
}
static int command_uptime(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
size_t d;
size_t h;
size_t m;
size_t D = (size_t) difftime(time(0), hub->tm_started);
d = D / (24 * 3600);
D = D % (24 * 3600);
h = D / 3600;
D = D % 3600;
m = D / 60;
tmp[0] = 0;
if (d)
{
strcat(tmp, uhub_itoa((int) d));
strcat(tmp, " day");
if (d != 1) strcat(tmp, "s");
strcat(tmp, ", ");
}
if (h < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) h));
strcat(tmp, ":");
if (m < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) m));
return command_status(hub, user, cmd, tmp);
}
static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
if (target == user)
return command_status(hub, user, cmd, "Cannot kick yourself");
hub_disconnect_user(hub, target, quit_kicked);
return command_status(hub, user, cmd, nick);
}
static int command_ban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
if (target == user)
return command_status(hub, user, cmd, "Cannot kick/ban yourself");
hub_disconnect_user(hub, target, quit_kicked);
acl_user_ban_nick(hub->acl, target->id.nick);
acl_user_ban_cid(hub->acl, target->id.cid);
return command_status(hub, user, cmd, nick);
}
static int command_unban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
return command_status(hub, user, cmd, "Not implemented");
}
static int command_reload(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
hub->status = hub_status_restart;
return command_status(hub, user, cmd, "Reloading configuration...");
}
static int command_shutdown(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
hub->status = hub_status_shutdown;
return command_status(hub, user, cmd, "Hub shutting down...");
}
static int command_version(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
return command_status(hub, user, cmd, "Powered by " PRODUCT "/" VERSION);
}
static int command_myip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
snprintf(tmp, 128, "Your address is \"%s\"", ip_convert_to_string(&user->net.ipaddr));
return command_status(hub, user, cmd, tmp);
}
static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
snprintf(tmp, 128, "%s has address \"%s\"", nick, ip_convert_to_string(&target->net.ipaddr));
return command_status(hub, user, cmd, tmp);
}
static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* address = list_get_first(cmd->args);
struct ip_range range;
struct linked_list* users;
struct hub_user* u;
int ret = 0;
ret = ip_convert_address_to_range(address, &range);
if (!ret)
return command_status(hub, user, cmd, "Invalid IP address/range/mask");
users = (struct linked_list*) list_create();
ret = uman_get_user_by_addr(hub, users, &range);
if (!ret)
{
list_destroy(users);
return command_status(hub, user, cmd, "No users found.");
}
char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d match%s:", cmd->prefix, (int) ret, ((ret != 1) ? "es" : ""));
char* buffer = hub_malloc(((MAX_NICK_LEN + INET6_ADDRSTRLEN + 5) * ret) + strlen(tmp) + 3);
buffer[0] = 0;
strcat(buffer, tmp);
strcat(buffer, "\n");
u = (struct hub_user*) list_get_first(users);
while (u)
{
strcat(buffer, u->id.nick);
strcat(buffer, " (");
strcat(buffer, ip_convert_to_string(&u->net.ipaddr));
strcat(buffer, ")\n");
u = (struct hub_user*) list_get_next(users);
}
strcat(buffer, "\n");
send_message(hub, user, buffer);
hub_free(buffer);
return 0;
}
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);
adc_msg_add_argument(command, (cmd->message + 10));
route_to_all(hub, command);
adc_msg_free(command);
return 0;
}
static int command_history(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* buffer;
struct linked_list* messages = hub->chat_history;
char* message = 0;
int ret = (int) list_size(messages);
size_t bufsize;
if (!ret)
{
return command_status(hub, user, cmd, "No messages.");
}
char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d message%s:", cmd->prefix, (int) ret, ((ret != 1) ? "s" : ""));
bufsize = strlen(tmp);
message = (char*) list_get_first(messages);
while (message)
{
bufsize += strlen(message);
message = (char*) list_get_next(messages);
}
buffer = hub_malloc(bufsize+4);
if (!buffer)
{
return command_status(hub, user, cmd, "Not enough memory.");
}
buffer[0] = 0;
strcat(buffer, tmp);
strcat(buffer, "\n");
message = (char*) list_get_first(messages);
while (message)
{
strcat(buffer, message);
message = (char*) list_get_next(messages);
}
strcat(buffer, "\n");
send_message(hub, user, buffer);
hub_free(buffer);
return 0;
}
static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
struct linked_list* messages = hub->logout_info;
struct hub_logout_info* log;
char tmp[1024];
char* search = 0;
size_t search_len = 0;
size_t search_hits = 0;
if (!list_size(messages))
{
return command_status(hub, user, cmd, "No entries logged.");
}
search = list_get_first(cmd->args);
if (search)
{
search_len = strlen(search);
}
if (search_len)
{
sprintf(tmp, "Logged entries: %d, searching for \"%s\"", (int) list_size(messages), search);
}
else
{
sprintf(tmp, "Logged entries: %d", (int) list_size(messages));
}
command_status(hub, user, cmd, tmp);
log = (struct hub_logout_info*) list_get_first(messages);
while (log)
{
const char* address = ip_convert_to_string(&log->addr);
int show = 0;
if (search_len)
{
if (memmem(log->cid, MAX_CID_LEN, search, search_len) || memmem(log->nick, MAX_NICK_LEN, search, search_len) || memmem(address, strlen(address), search, search_len))
{
search_hits++;
show = 1;
}
}
else
{
show = 1;
}
if (show)
{
sprintf(tmp, "* %s %s, %s [%s] - %s", get_timestamp(log->time), log->cid, log->nick, ip_convert_to_string(&log->addr), user_get_quit_reason_string(log->reason));
send_message(hub, user, tmp);
}
log = (struct hub_logout_info*) list_get_next(messages);
}
if (search_len)
{
sprintf(tmp, "%d entries shown.", (int) search_hits);
command_status(hub, user, cmd, tmp);
}
return 0;
}
#ifdef CRASH_DEBUG
static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
void (*crash)(void) = NULL;
crash();
return 0;
}
#endif
int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message)
{
size_t n = 0;
int rc;
/* Parse and validate the command */
struct hub_command* cmd = command_create(message);
if (!cmd) return 1;
for (n = 0; command_handlers[n].prefix; n++)
{
struct commands_handler* handler = &command_handlers[n];
if (cmd->prefix_len != handler->length)
continue;
if (!strncmp(cmd->prefix, handler->prefix, handler->length))
{
if (handler->cred <= user->credentials)
{
if (!handler->args || (handler->args && list_size(cmd->args) >= strlen(handler->args)))
{
rc = handler->handler(hub, user, cmd);
}
else
{
rc = command_arg_mismatch(hub, user, cmd, handler);
}
command_destroy(cmd);
return rc;
}
else
{
rc = command_access_denied(hub, user, cmd);
command_destroy(cmd);
return rc;
}
}
}
command_not_found(hub, user, cmd);
command_destroy(cmd);
return 1;
}
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" },
{ "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" },
{ "log", 3, 0, cred_operator, command_log, "Display log" },
#ifdef CRASH_DEBUG
{ "crash", 5, 0, cred_admin, command_crash, "Crash the hub (DEBUG)." },
#endif
{ 0, 0, 0, cred_none, command_help, "" }
};

View File

@@ -1,96 +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/>.
*
*/
#include "uhub.h"
static void log_user_login(struct hub_user* u)
{
const char* cred = get_user_credential_string(u->credentials);
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("LoginOK %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, cred, u->user_agent);
}
static void log_user_login_error(struct hub_user* u, enum status_message msg)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
const char* message = hub_get_status_message_log(u->hub, msg);
LOG_USER("LoginError %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message, u->user_agent);
}
static void log_user_logout(struct hub_user* u, const char* message)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("Logout %s/%s %s \"%s\" (%s)", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message);
}
static void log_user_nick_change(struct hub_user* u, const char* nick)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick);
}
/* Send MOTD, do logging etc */
void on_login_success(struct hub_info* hub, struct hub_user* u)
{
/* Send user list of all existing users */
if (!uman_send_user_list(hub, u))
return;
/* Mark as being in the normal state, and add user to the user list */
user_set_state(u, state_normal);
uman_add(hub, u);
/* Print log message */
log_user_login(u);
/* Announce new user to all connected users */
if (user_is_logged_in(u))
route_info_message(hub, u);
/* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(hub, u);
/* reset to idle timeout */
user_set_timeout(u, TIMEOUT_IDLE);
}
void on_login_failure(struct hub_info* hub, struct hub_user* u, enum status_message msg)
{
log_user_login_error(u, msg);
hub_send_status(hub, u, msg, status_level_fatal);
hub_disconnect_user(hub, u, quit_logon_error);
}
void on_nick_change(struct hub_info* hub, struct hub_user* u, const char* nick)
{
if (user_is_logged_in(u))
{
log_user_nick_change(u, nick);
}
}
void on_logout_user(struct hub_info* hub, struct hub_user* user)
{
const char* reason = user_get_quit_reason_string(user->quit_reason);
log_user_logout(user, reason);
hub_logout_log(hub, user);
}

View File

@@ -1,213 +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/>.
*
*/
#include "uhub.h"
#include "hubio.h"
// #define SEND_CHUNKS 1
/* FIXME: This should not be needed! */
extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ
static void debug_msg(const char* prefix, struct adc_message* msg)
{
size_t n;
char* buf = strdup(msg->cache);
for (n = 0; n < msg->length; n++)
{
if (buf[n] == '\r' || buf[n] == '\n')
buf[n] = '_';
}
LOG_TRACE("%s: [%s] (%d bytes)", prefix, buf, (int) msg->length);
free(buf);
}
#endif
struct hub_recvq* hub_recvq_create()
{
struct hub_recvq* q = hub_malloc_zero(sizeof(struct hub_recvq));
return q;
}
void hub_recvq_destroy(struct hub_recvq* q)
{
if (q)
{
hub_free(q->buf);
hub_free(q);
}
}
size_t hub_recvq_get(struct hub_recvq* q, void* buf, size_t bufsize)
{
assert(bufsize >= q->size);
if (q->size)
{
size_t n = q->size;
memcpy(buf, q->buf, n);
hub_free(q->buf);
q->buf = 0;
q->size = 0;
return n;
}
return 0;
}
size_t hub_recvq_set(struct hub_recvq* q, void* buf, size_t bufsize)
{
if (q->buf)
{
hub_free(q->buf);
q->buf = 0;
q->size = 0;
}
if (!bufsize)
{
return 0;
}
q->buf = hub_malloc(bufsize);
if (!q->buf)
return 0;
q->size = bufsize;
memcpy(q->buf, buf, bufsize);
return bufsize;
}
struct hub_sendq* hub_sendq_create()
{
struct hub_sendq* q = hub_malloc_zero(sizeof(struct hub_sendq));
if (!q)
return 0;
q->queue = list_create();
if (!q->queue)
{
hub_free(q);
return 0;
}
return q;
}
static void clear_send_queue_callback(void* ptr)
{
adc_msg_free((struct adc_message*) ptr);
}
void hub_sendq_destroy(struct hub_sendq* q)
{
if (q)
{
list_clear(q->queue, &clear_send_queue_callback);
list_destroy(q->queue);
hub_free(q);
}
}
void hub_sendq_add(struct hub_sendq* q, struct adc_message* msg_)
{
struct adc_message* msg = adc_msg_incref(msg_);
#ifdef DEBUG_SENDQ
debug_msg("hub_sendq_add", msg);
#endif
list_append(q->queue, msg);
q->size += msg->length;
}
void hub_sendq_remove(struct hub_sendq* q, struct adc_message* msg)
{
#ifdef DEBUG_SENDQ
debug_msg("hub_sendq_remove", msg);
#endif
list_remove(q->queue, msg);
q->size -= msg->length;
adc_msg_free(msg);
q->offset = 0;
}
int hub_sendq_send(struct hub_sendq* q, hub_recvq_write w, void* data)
{
int ret = 0;
size_t bytes = 0;
size_t offset = q->offset; // offset into first message.
size_t remain = 0;
size_t length = 0;
char* sbuf = g_hub->sendbuf;
size_t max_send_buf = 4096;
/* Copy as many messages possible into global send queue */
struct adc_message* msg = list_get_first(q->queue);
while (msg)
{
length = MIN(msg->length - offset, (max_send_buf-1) - bytes);
memcpy(sbuf + bytes, msg->cache + offset, length);
bytes += length;
if (length < (msg->length - offset))
break;
offset = 0;
msg = list_get_next(q->queue);
}
msg = list_get_first(q->queue);
/* Send as much as possible */
ret = w(data, sbuf, bytes);
if (ret > 0)
{
#ifdef SSL_SUPPORT
q->last_write_n = ret;
#endif
/* Remove messages sent */
offset = q->offset;
remain = ret;
while (msg)
{
length = msg->length - offset;
if (length >= remain)
{
q->offset += remain;
break;
}
remain -= length;
hub_sendq_remove(q, msg);
msg = list_get_next(q->queue);
offset = 0;
}
}
return ret;
}
int hub_sendq_is_empty(struct hub_sendq* q)
{
return (q->size - q->offset) == 0;
}
size_t hub_sendq_get_bytes(struct hub_sendq* q)
{
return q->size - q->offset;
}

View File

@@ -1,107 +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/>.
*
*/
#ifndef HAVE_UHUB_HUB_IO_H
#define HAVE_UHUB_HUB_IO_H
struct adc_message;
struct linked_list;
typedef int (*hub_recvq_write)(void* desc, const void* buf, size_t len);
typedef int (*hub_recvq_read)(void* desc, void* buf, size_t len);
struct hub_sendq
{
size_t size; /** Size of send queue (in bytes, not messages) */
size_t offset; /** Queue byte offset in the first message. Should be 0 unless a partial write. */
#ifdef SSL_SUPPORT
size_t last_send; /** When using SSL, one have to send the exact same buffer and length if a write cannot complete. */
#endif
struct linked_list* queue; /** List of queued messages */
};
struct hub_recvq
{
char* buf;
size_t size;
};
/**
* Create a send queue
*/
extern struct hub_sendq* hub_sendq_create();
/**
* Destroy a send queue, and delete any queued messages.
*/
extern void hub_sendq_destroy(struct hub_sendq*);
/**
* Add a message to the send queue.
*/
extern void hub_sendq_add(struct hub_sendq*, struct adc_message* msg);
/**
* Process the send queue, and send as many messages as possible.
* @returns the number of bytes sent.
* FIXME: send error not handled here!
*/
extern int hub_sendq_send(struct hub_sendq*, hub_recvq_write, void* data);
/**
* @returns 1 if send queue is empty, 0 otherwise.
*/
extern int hub_sendq_is_empty(struct hub_sendq*);
/**
* @returns the number of bytes remaining to be sent in the queue.
*/
extern size_t hub_sendq_get_bytes(struct hub_sendq*);
/**
* Create a receive queue.
*/
extern struct hub_recvq* hub_recvq_create();
/**
* Destroy a receive queue.
*/
extern void hub_recvq_destroy(struct hub_recvq*);
/**
* Gets the buffer, copies it into buf and deallocates it.
* NOTE: bufsize *MUST* be larger than the buffer, otherwise it asserts.
* @return the number of bytes copied into buf.
*/
extern size_t hub_recvq_get(struct hub_recvq*, void* buf, size_t bufsize);
/**
* Sets the buffer
*/
extern size_t hub_recvq_set(struct hub_recvq*, void* buf, size_t bufsize);
/**
* @return 1 if size is zero, 0 otherwise.
*/
extern int hub_recvq_is_empty(struct hub_recvq* buf);
#endif /* HAVE_UHUB_HUB_IO_H */

View File

@@ -1,350 +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/>.
*
*/
#include "uhub.h"
#include "hubio.h"
/* FIXME: This should not be needed! */
extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ
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);
if (sent == -1)
{
int err = net_error();
LOG_DUMP(" errno: %d - %s\n", err, net_error_string(err));
}
}
void debug_sendq_recv(struct hub_user* user, int received, int max, const char* buffer)
{
LOG_DUMP("RECV: %d/%d bytes\n", received, (int) max);
if (received == -1)
{
int err = net_error();
LOG_DUMP(" errno: %d - %s\n", err, net_error_string(err));
}
else if (received > 0)
{
char* data = hub_malloc_zero(received + 1);
memcpy(data, buffer, received);
LOG_DUMP("RECV: \"%s\"\n", data);
hub_free(data);
}
}
#endif
int net_user_send(void* ptr, const void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = net_send(user->net.connection.sd, buf, len, UHUB_SEND_SIGNAL);
#ifdef DEBUG_SENDQ
debug_sendq_send(user, ret, len);
#endif
if (ret > 0)
{
user_reset_last_write(user);
}
else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR))
{
return -2;
}
else
{
// user->close_flag = quit_socket_error;
return 0;
}
return ret;
}
#ifdef SSL_SUPPORT
int net_user_send_ssl(void* ptr, const void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = SSL_write(user->net.ssl, buf, (int) len);
#ifdef DEBUG_SENDQ
debug_sendq_send(user, ret, len);
#endif
if (ret > 0)
{
user_reset_last_write(user);
}
else if (ret == -1 && net_error() == EWOULDBLOCK)
{
return -2;
}
else
{
// user->close_flag = quit_socket_error;
return 0;
}
return ret;
}
#endif
int net_user_recv(void* ptr, void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = net_recv(user->net.connection.sd, buf, len, 0);
if (ret > 0)
{
user_reset_last_read(user);
}
#ifdef DEBUG_SENDQ
debug_sendq_recv(user, ret, len, buf);
#endif
return ret;
}
#ifdef SSL_SUPPORT
int net_user_recv_ssl(void* ptr, void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = SSL_read(user->net.ssl, buf, len);
if (ret > 0)
{
user_reset_last_read(user);
}
#ifdef DEBUG_SENDQ
debug_sendq_recv(user, ret, len, buf);
#endif
return ret;
}
#endif
int handle_net_read(struct hub_user* user)
{
static char buf[MAX_RECV_BUF];
struct hub_recvq* q = user->net.recv_queue;
size_t buf_size = hub_recvq_get(q, buf, MAX_RECV_BUF);
ssize_t size = net_user_recv(user, &buf[buf_size], MAX_RECV_BUF - buf_size);
if (size > 0)
buf_size += size;
if (size == -1)
{
if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0;
return quit_socket_error;
}
else if (size == 0)
{
return quit_disconnected;
}
else
{
char* lastPos = 0;
char* start = buf;
char* pos = 0;
size_t remaining = buf_size;
while ((pos = memchr(start, '\n', remaining)))
{
lastPos = pos;
pos[0] = '\0';
#ifdef DEBUG_SENDQ
LOG_DUMP("PROC: \"%s\" (%d)\n", start, (int) (pos - start));
#endif
if (user_flag_get(user, flag_maxbuf))
{
user_flag_unset(user, flag_maxbuf);
}
else
{
if (((pos - start) > 0) && g_hub->config->max_recv_buffer > (pos - start))
{
if (hub_handle_message(g_hub, user, start, (pos - start)) == -1)
{
return quit_protocol_error;
break;
}
}
}
pos[0] = '\n'; /* FIXME: not needed */
pos ++;
remaining -= (pos - start);
start = pos;
}
if (lastPos)
{
if (remaining < g_hub->config->max_recv_buffer)
{
hub_recvq_set(q, lastPos, remaining);
}
else
{
hub_recvq_set(q, 0, 0);
user_flag_set(user, flag_maxbuf);
}
}
else
{
hub_recvq_set(q, 0, 0);
}
}
return 0;
}
int handle_net_write(struct hub_user* user)
{
while (hub_sendq_get_bytes(user->net.send_queue))
{
int ret = hub_sendq_send(user->net.send_queue, net_user_send, user);
if (ret == -2)
break;
if (ret <= 0)
return quit_socket_error;
}
if (hub_sendq_get_bytes(user->net.send_queue))
{
user_net_io_want_write(user);
}
else
{
user_net_io_want_read(user);
}
return 0;
}
void net_event(int fd, short ev, void *arg)
{
struct hub_user* user = (struct hub_user*) arg;
int flag_close = 0;
#ifdef DEBUG_SENDQ
LOG_TRACE("net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg);
#endif
if (ev & EV_TIMEOUT)
{
if (user_is_connecting(user))
{
flag_close = quit_timeout;
}
else
{
// FIXME: hub is not neccesarily set!
// hub_send_ping(hub, user);
}
}
if (ev & EV_READ)
{
flag_close = handle_net_read(user);
}
else if (ev & EV_WRITE)
{
flag_close = handle_net_write(user);
}
if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
}
static void prepare_user_net(struct hub_info* hub, struct hub_user* user)
{
int fd = user->net.connection.sd;
#ifdef SET_SENDBUG
size_t sendbuf = 0;
size_t recvbuf = 0;
if (net_get_recvbuf_size(fd, &recvbuf) != -1)
{
if (recvbuf > MAX_RECV_BUF || !recvbuf) recvbuf = MAX_RECV_BUF;
net_set_recvbuf_size(fd, recvbuf);
}
if (net_get_sendbuf_size(fd, &sendbuf) != -1)
{
if (sendbuf > MAX_SEND_BUF || !sendbuf) sendbuf = MAX_SEND_BUF;
net_set_sendbuf_size(fd, sendbuf);
}
#endif
net_set_nonblocking(fd, 1);
net_set_nosigpipe(fd, 1);
}
void net_on_accept(int server_fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct hub_user* user = 0;
struct ip_addr_encap ipaddr;
const char* addr;
for (;;)
{
int fd = net_accept(server_fd, &ipaddr);
if (fd == -1)
{
if (net_error() == EWOULDBLOCK)
{
break;
}
else
{
LOG_ERROR("Accept error: %d %s", net_error(), strerror(net_error()));
break;
}
}
addr = ip_convert_to_string(&ipaddr);
/* FIXME: Should have a plugin log this */
LOG_TRACE("Got connection from %s", addr);
/* FIXME: A plugin should perform this check: is IP banned? */
if (acl_is_ip_banned(hub->acl, addr))
{
LOG_INFO("Denied [%s] (IP banned)", addr);
net_close(fd);
continue;
}
user = user_create(hub, fd);
if (!user)
{
LOG_ERROR("Unable to create user after socket accepted. Out of memory?");
net_close(fd);
break;
}
/* Store IP address in user object */
memcpy(&user->net.ipaddr, &ipaddr, sizeof(ipaddr));
prepare_user_net(hub, user);
}
}

View File

@@ -1,219 +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/>.
*
*/
#include "uhub.h"
int route_message(struct hub_info* hub, struct hub_user* u, struct adc_message* msg)
{
struct hub_user* target = NULL;
switch (msg->cache[0])
{
case 'B': /* Broadcast to all logged in clients */
route_to_all(hub, msg);
break;
case 'D':
target = uman_get_user_by_sid(hub, msg->target);
if (target)
{
route_to_user(hub, target, msg);
}
break;
case 'E':
target = uman_get_user_by_sid(hub, msg->target);
if (target)
{
route_to_user(hub, target, msg);
route_to_user(hub, u, msg);
}
break;
case 'F':
route_to_subscribers(hub, msg);
break;
default:
/* Ignore the message */
break;
}
return 0;
}
static inline size_t get_max_send_queue(struct hub_info* hub)
{
/* TODO: More dynamic send queue limit, for instance:
* return MAX(hub->config->max_send_buffer, (hub->config->max_recv_buffer * hub_get_user_count(hub)));
*/
return hub->config->max_send_buffer;
}
static inline size_t get_max_send_queue_soft(struct hub_info* hub)
{
return hub->config->max_send_buffer_soft;
}
/*
* @return 1 if send queue is OK.
* -1 if send queue is overflowed
* 0 if soft send queue is overflowed (not implemented at the moment)
*/
static inline int check_send_queue(struct hub_info* hub, struct hub_user* user, struct adc_message* msg)
{
if (user_flag_get(user, flag_user_list))
return 1;
if ((user->net.send_queue->size + msg->length) > get_max_send_queue(hub))
return -1;
if (user->net.send_queue->size > get_max_send_queue_soft(hub) && msg->priority < 0)
return 0;
return 1;
}
int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_message* msg)
{
#ifdef DEBUG_SENDQ
char* data = strndup(msg->cache, msg->length-1);
LOG_PROTO("send %s: \"%s\"", sid_to_string(user->id.sid), data);
free(data);
#endif
if (hub_sendq_is_empty(user->net.send_queue) && !user_flag_get(user, flag_pipeline))
{
/* Perform oportunistic write */
hub_sendq_add(user->net.send_queue, msg);
handle_net_write(user);
}
else
{
if (check_send_queue(hub, user, msg) >= 0)
{
hub_sendq_add(user->net.send_queue, msg);
if (!user_flag_get(user, flag_pipeline))
user_net_io_want_write(user);
}
}
return 1;
}
int route_flush_pipeline(struct hub_info* hub, struct hub_user* u)
{
if (hub_sendq_is_empty(u->net.send_queue))
return 0;
handle_net_write(u);
user_flag_unset(u, flag_pipeline);
return 1;
}
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
route_to_user(hub, user, command);
user = (struct hub_user*) list_get_next(hub->users->list);
}
return 0;
}
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
int do_send;
char* tmp;
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (user->feature_cast)
{
do_send = 1;
tmp = list_get_first(command->feature_cast_include);
while (tmp)
{
if (!user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_include);;
}
if (!do_send) {
user = (struct hub_user*) list_get_next(hub->users->list);
continue;
}
tmp = list_get_first(command->feature_cast_exclude);
while (tmp)
{
if (user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_exclude);
}
if (do_send)
{
route_to_user(hub, user, command);
}
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
return 0;
}
int route_info_message(struct hub_info* hub, struct hub_user* u)
{
if (!user_is_nat_override(u))
{
return route_to_all(hub, u->info);
}
else
{
struct adc_message* cmd = adc_msg_copy(u->info);
const char* address = ip_convert_to_string(&u->net.ipaddr);
struct hub_user* user = 0;
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (user_is_nat_override(user))
route_to_user(hub, user, cmd);
else
route_to_user(hub, user, u->info);
user = (struct hub_user*) list_get_next(hub->users->list);
}
adc_msg_free(cmd);
}
return 0;
}

View File

@@ -1,375 +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/>.
*
*/
#include "uhub.h"
#ifdef DEBUG_SENDQ
static const char* user_log_str(struct hub_user* user)
{
static char buf[128];
if (user)
{
snprintf(buf, 128, "user={ %p, \"%s\", %s/%s}", user, user->id.nick, sid_to_string(user->id.sid), user->id.cid);
}
else
{
snprintf(buf, 128, "user={ %p }", user);
}
return buf;
}
#endif
struct hub_user* user_create(struct hub_info* hub, int sd)
{
struct hub_user* user = NULL;
LOG_TRACE("user_create(), hub=%p, sd=%d", hub, sd);
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL)
return NULL; /* OOM */
user->net.tm_connected = time(NULL);
user->net.send_queue = hub_sendq_create();
user->net.recv_queue = hub_recvq_create();
net_con_initialize(&user->net.connection, sd, user, EV_READ);
evtimer_set(&user->net.timeout, net_event, user);
event_base_set(hub->evbase, &user->net.timeout);
user_set_timeout(user, TIMEOUT_CONNECTED);
user_set_state(user, state_protocol);
return user;
}
void user_destroy(struct hub_user* user)
{
LOG_TRACE("user_destroy(), user=%p", user);
net_con_close(&user->net.connection);
evtimer_del(&user->net.timeout);
hub_recvq_destroy(user->net.recv_queue);
hub_sendq_destroy(user->net.send_queue);
adc_msg_free(user->info);
user_clear_feature_cast_support(user);
hub_free(user);
}
void user_set_state(struct hub_user* user, enum user_state state)
{
if ((user->state == state_cleanup && state != state_disconnected) || (user->state == state_disconnected))
{
return;
}
user->state = state;
}
void user_set_info(struct hub_user* user, struct adc_message* cmd)
{
adc_msg_free(user->info);
user->info = adc_msg_incref(cmd);
}
void user_update_info(struct hub_user* u, struct adc_message* cmd)
{
char prefix[2];
char* argument;
size_t n = 0;
struct adc_message* cmd_new = adc_msg_copy(u->info);
if (!cmd_new)
{
/* FIXME: OOM! */
return;
}
/*
* FIXME: Optimization potential:
*
* remove parts of cmd that do not really change anything in cmd_new.
* this can save bandwidth if clients send multiple updates for information
* that does not really change anything.
*/
argument = adc_msg_get_argument(cmd, n++);
while (argument)
{
if (strlen(argument) >= 2)
{
prefix[0] = argument[0];
prefix[1] = argument[1];
adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
}
hub_free(argument);
argument = adc_msg_get_argument(cmd, n++);
}
user_set_info(u, cmd_new);
adc_msg_free(cmd_new);
}
static int convert_support_fourcc(int fourcc)
{
switch (fourcc)
{
case FOURCC('B','A','S','0'): /* Obsolete */
#ifndef OLD_ADC_SUPPORT
return 0;
#endif
case FOURCC('B','A','S','E'):
return feature_base;
case FOURCC('A','U','T','0'):
return feature_auto;
case FOURCC('U','C','M','0'):
case FOURCC('U','C','M','D'):
return feature_ucmd;
case FOURCC('Z','L','I','F'):
return feature_zlif;
case FOURCC('B','B','S','0'):
return feature_bbs;
case FOURCC('T','I','G','R'):
return feature_tiger;
case FOURCC('B','L','O','M'):
case FOURCC('B','L','O','0'):
return feature_bloom;
case FOURCC('P','I','N','G'):
return feature_ping;
case FOURCC('L','I','N','K'):
return feature_link;
default:
LOG_DEBUG("Unknown extension: %x", fourcc);
return 0;
}
}
void user_support_add(struct hub_user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags |= feature_mask;
}
int user_flag_get(struct hub_user* user, enum user_flags flag)
{
return user->flags & flag;
}
void user_flag_set(struct hub_user* user, enum user_flags flag)
{
user->flags |= flag;
}
void user_flag_unset(struct hub_user* user, enum user_flags flag)
{
user->flags &= ~flag;
}
void user_set_nat_override(struct hub_user* user)
{
user_flag_set(user, flag_nat);
}
int user_is_nat_override(struct hub_user* user)
{
return user_flag_get(user, flag_nat);
}
void user_support_remove(struct hub_user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags &= ~feature_mask;
}
int user_have_feature_cast_support(struct hub_user* user, char feature[4])
{
char* tmp = list_get_first(user->feature_cast);
while (tmp)
{
if (strncmp(tmp, feature, 4) == 0)
return 1;
tmp = list_get_next(user->feature_cast);
}
return 0;
}
int user_set_feature_cast_support(struct hub_user* u, char feature[4])
{
if (!u->feature_cast)
{
u->feature_cast = list_create();
}
if (!u->feature_cast)
{
return 0; /* OOM! */
}
list_append(u->feature_cast, hub_strndup(feature, 4));
return 1;
}
void user_clear_feature_cast_support(struct hub_user* u)
{
if (u->feature_cast)
{
list_clear(u->feature_cast, &hub_free);
list_destroy(u->feature_cast);
u->feature_cast = 0;
}
}
int user_is_logged_in(struct hub_user* user)
{
if (user->state == state_normal)
return 1;
return 0;
}
int user_is_connecting(struct hub_user* user)
{
if (user->state == state_protocol || user->state == state_identify || user->state == state_verify)
return 1;
return 0;
}
int user_is_protocol_negotiating(struct hub_user* user)
{
if (user->state == state_protocol)
return 1;
return 0;
}
int user_is_disconnecting(struct hub_user* user)
{
if (user->state == state_cleanup || user->state == state_disconnected)
return 1;
return 0;
}
int user_is_protected(struct hub_user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
/**
* Returns 1 if a user is registered.
* Only registered users will be let in if the hub is configured for registered
* users only.
*/
int user_is_registered(struct hub_user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_user:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
void user_net_io_want_write(struct hub_user* user)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_net_io_want_write: %s (pending: %d)", user_log_str(user), event_pending(&user->net.event, EV_READ | EV_WRITE, 0));
#endif
net_con_update(&user->net.connection, EV_READ | EV_WRITE);
}
void user_net_io_want_read(struct hub_user* user)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_net_io_want_read: %s (pending: %d)", user_log_str(user), event_pending(&user->net.event, EV_READ | EV_WRITE, 0));
#endif
net_con_update(&user->net.connection, EV_READ);
}
void user_reset_last_write(struct hub_user* user)
{
user->net.tm_last_write = time(NULL);
}
void user_reset_last_read(struct hub_user* user)
{
user->net.tm_last_read = time(NULL);
}
void user_set_timeout(struct hub_user* user, int seconds)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_set_timeout to %d seconds: %s", seconds, user_log_str(user));
#endif
struct timeval timeout = { seconds, 0 };
evtimer_add(&user->net.timeout, &timeout);
}
const char* user_get_quit_reason_string(enum user_quit_reason reason)
{
switch (reason)
{
case quit_unknown: return "unknown"; break;
case quit_disconnected: return "disconnected"; break;
case quit_kicked: return "kicked"; break;
case quit_banned: return "banned"; break;
case quit_timeout: return "timeout"; break;
case quit_send_queue: return "send queue"; break;
case quit_memory_error: return "out of memory"; break;
case quit_socket_error: return "socket error"; break;
case quit_protocol_error: return "protocol error"; break;
case quit_logon_error: return "login error"; break;
case quit_hub_disabled: return "hub disabled"; break;
case quit_ghost_timeout: return "ghost"; break;
}
return "unknown";
}

View File

@@ -22,7 +22,7 @@
#ifdef EQ_DEBUG
static void eq_debug(const char* prefix, struct event_data* data)
{
LOG_DUMP(">>> %s: %p, id: %x, flags=%d\n", prefix, data, data->id, data->flags);
printf(">>> %s: %p, id: %x, flags=%d\n", prefix, data, data->id, data->flags);
}
#endif
@@ -130,7 +130,7 @@ void event_queue_post(struct event_queue* queue, struct event_data* message)
}
else
{
LOG_ERROR("event_queue_post: OUT OF MEMORY");
hub_log(log_error, "event_queue_post: OUT OF MEMORY");
}
}

View File

@@ -19,14 +19,14 @@
#include "uhub.h"
struct hub_info* g_hub = 0;
int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* line, size_t length)
int hub_handle_message(struct hub_info* hub, struct user* u, const char* line, size_t length)
{
int ret = 0;
struct adc_message* cmd = 0;
LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);
#ifdef NETWORK_DUMP_DEBUG
hub_log(log_protocol, "recv %s: %s", sid_to_string(u->id.sid), line);
#endif
if (user_is_disconnecting(u))
return -1;
@@ -70,7 +70,7 @@ int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* lin
default:
if (user_is_logged_in(u))
{
ret = route_message(hub, u, cmd);
ret = route_message(u, cmd);
}
else
{
@@ -92,12 +92,13 @@ int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* lin
}
int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
int hub_handle_support(struct hub_info* hub, struct user* u, struct adc_message* cmd)
{
int ret = 0;
int index = 0;
int ok = 1;
char* arg = adc_msg_get_argument(cmd, index);
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
if (hub->status == hub_status_disabled && u->state == state_protocol)
{
@@ -141,12 +142,13 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
if (ok)
{
hub_send_handshake(hub, u);
user_set_timeout(u, TIMEOUT_HANDSHAKE);
if (u->ev_read)
event_add(u->ev_read, &timeout);
}
else
{
/* disconnect user. Do not send crap during initial handshake! */
hub_disconnect_user(hub, u, quit_logon_error);
user_disconnect(u, quit_logon_error);
ret = -1;
}
}
@@ -155,14 +157,14 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
}
int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
int hub_handle_password(struct hub_info* hub, struct user* u, struct adc_message* cmd)
{
char* password = adc_msg_get_argument(cmd, 0);
int ret = 0;
if (u->state == state_verify)
{
if (acl_password_verify(hub->acl, u, password))
if (password_verify(u, password))
{
on_login_success(hub, u);
}
@@ -178,80 +180,52 @@ int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_mes
}
int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
int hub_handle_chat_message(struct hub_info* hub, struct user* u, struct adc_message* cmd)
{
char* message = adc_msg_get_argument(cmd, 0);
int ret = 0;
int relay = 1;
/* TODO: Check for hub-commands here. Set relay to 0 and the message will not be sent to other users. */
if (message[0] == '!' || message[0] == '+')
{
relay = command_dipatcher(hub, u, message);
}
if (hub->config->chat_is_privileged && !user_is_protected(u) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F'))
{
relay = 0;
}
if (relay && user_is_logged_in(u))
{
/* adc_msg_remove_named_argument(cmd, "PM"); */
if (cmd->cache[0] == 'B')
hub_chat_history_add(hub, u, cmd);
ret = route_message(hub, u, cmd);
ret = route_message(u, cmd);
}
hub_free(message);
free(message);
return ret;
}
void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
char* msg_esc = adc_msg_get_argument(cmd, 0);
char* message = adc_msg_unescape(msg_esc);
char* log = hub_malloc(strlen(message) + strlen(user->id.nick) + 14);
sprintf(log, "%s <%s> %s\n", get_timestamp(time(NULL)), user->id.nick, message);
list_append(hub->chat_history, log);
while (list_size(hub->chat_history) > (size_t) hub->config->max_chat_history)
{
char* msg = list_get_first(hub->chat_history);
list_remove(hub->chat_history, msg);
hub_free(msg);
}
hub_free(message);
hub_free(msg_esc);
}
void hub_chat_history_clear(struct hub_info* hub)
{
list_clear(hub->chat_history, &hub_free);
}
void hub_send_support(struct hub_info* hub, struct hub_user* u)
void hub_send_support(struct hub_info* hub, struct user* u)
{
if (user_is_connecting(u) || user_is_logged_in(u))
{
route_to_user(hub, u, hub->command_support);
route_to_user(u, hub->command_support);
}
}
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
void hub_send_sid(struct hub_info* hub, struct user* u)
{
sid_t sid;
struct adc_message* command;
if (user_is_connecting(u))
{
command = adc_msg_construct(ADC_CMD_ISID, 10);
sid = uman_get_free_sid(hub, u);
adc_msg_add_argument(command, (const char*) sid_to_string(sid));
route_to_user(hub, u, command);
u->id.sid = uman_get_free_sid(hub);
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
route_to_user(u, command);
adc_msg_free(command);
}
}
void hub_send_ping(struct hub_info* hub, struct hub_user* user)
void hub_send_ping(struct hub_info* hub, struct user* user)
{
/* This will just send a newline, despite appearing to do more below. */
struct adc_message* ping = adc_msg_construct(0, 0);
@@ -259,12 +233,12 @@ void hub_send_ping(struct hub_info* hub, struct hub_user* user)
ping->cache[1] = 0;
ping->length = 1;
ping->priority = 1;
route_to_user(hub, user, ping);
route_to_user(user, ping);
adc_msg_free(ping);
}
void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
void hub_send_hubinfo(struct hub_info* hub, struct user* u)
{
struct adc_message* info = adc_msg_copy(hub->command_info);
int value = 0;
@@ -319,24 +293,22 @@ void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
if (user_is_connecting(u) || user_is_logged_in(u))
{
route_to_user(hub, u, info);
route_to_user(u, info);
}
adc_msg_free(info);
/* Only send banner when connecting */
if (hub->config->show_banner && user_is_connecting(u))
{
route_to_user(hub, u, hub->command_banner);
route_to_user(u, hub->command_banner);
}
}
void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
void hub_send_handshake(struct hub_info* hub, struct user* u)
{
user_flag_set(u, flag_pipeline);
hub_send_support(hub, u);
hub_send_sid(hub, u);
hub_send_hubinfo(hub, u);
route_flush_pipeline(hub, u);
if (!user_is_disconnecting(u))
{
@@ -344,60 +316,62 @@ void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
}
}
void hub_send_motd(struct hub_info* hub, struct hub_user* u)
void hub_send_motd(struct hub_info* hub, struct user* u)
{
if (hub->command_motd)
{
route_to_user(hub, u, hub->command_motd);
route_to_user(u, hub->command_motd);
}
}
void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
void hub_send_password_challenge(struct hub_info* hub, struct user* u)
{
struct adc_message* igpa;
igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
adc_msg_add_argument(igpa, acl_password_generate_challenge(hub->acl, u));
adc_msg_add_argument(igpa, password_generate_challenge(u));
user_set_state(u, state_verify);
route_to_user(hub, u, igpa);
route_to_user(u, igpa);
adc_msg_free(igpa);
}
static void hub_event_dispatcher(void* callback_data, struct event_data* message)
{
struct hub_info* hub = (struct hub_info*) callback_data;
struct hub_user* user = (struct hub_user*) message->ptr;
assert(hub != NULL);
/*
hub_log(log_trace, "hub_event_dispatcher: %x (ptr=%p)", message->id, message->ptr);
*/
switch (message->id)
{
case UHUB_EVENT_USER_JOIN:
{
if (user_is_disconnecting(user))
if (user_is_disconnecting((struct user*) message->ptr))
break;
if (message->flags)
{
hub_send_password_challenge(hub, user);
hub_send_password_challenge(hub, (struct user*) message->ptr);
}
else
{
on_login_success(hub, user);
on_login_success(hub, (struct user*) message->ptr);
}
break;
}
case UHUB_EVENT_USER_QUIT:
{
uman_remove(hub, user);
uman_send_quit_message(hub, user);
on_logout_user(hub, user);
hub_schedule_destroy_user(hub, user);
uman_remove(hub, (struct user*) message->ptr);
uman_send_quit_message((struct user*) message->ptr);
on_logout_user(hub, (struct user*) message->ptr);
user_schedule_destroy((struct user*) message->ptr);
break;
}
case UHUB_EVENT_USER_DESTROY:
{
user_destroy(user);
hub_log(log_trace, "hub_event_dispatcher: UHUB_EVENT_USER_DESTROY (ptr=%p)", message->ptr);
user_destroy((struct user*) message->ptr);
break;
}
@@ -419,7 +393,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
hub = hub_malloc_zero(sizeof(struct hub_info));
if (!hub)
{
LOG_FATAL("Unable to allocate memory for hub");
hub_log(log_fatal, "Unable to allocate memory for hub");
return 0;
}
@@ -428,9 +402,9 @@ struct hub_info* hub_start_service(struct hub_config* config)
ipv6_supported = net_is_ipv6_supported();
if (ipv6_supported)
LOG_DEBUG("IPv6 supported.");
hub_log(log_debug, "IPv6 supported.");
else
LOG_DEBUG("IPv6 not supported.");
hub_log(log_debug, "IPv6 not supported.");
if (ip_convert_address(config->server_bind_addr, config->server_port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
{
@@ -455,13 +429,13 @@ struct hub_info* hub_start_service(struct hub_config* config)
#endif
if (!hub->evbase)
{
LOG_ERROR("Unable to initialize libevent.");
hub_log(log_error, "Unable to initialize libevent.");
hub_free(hub);
return 0;
}
LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
LOG_DEBUG("Using libevent %s, backend: %s", event_get_version(), event_get_method());
hub_log(log_info, "Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
hub_log(log_debug, "Using libevent %s, backend: %s", event_get_version(), event_get_method());
server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
if (server_tcp == -1)
@@ -492,7 +466,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
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_log(log_fatal, "hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
@@ -502,7 +476,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
ret = net_listen(server_tcp, SERVER_BACKLOG);
if (ret == -1)
{
LOG_FATAL("hub_start_service(): Unable to listen to socket");
hub_log(log_fatal, "hub_start_service(): Unable to listen to socket");
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
@@ -538,42 +512,15 @@ struct hub_info* hub_start_service(struct hub_config* config)
return 0;
}
hub->recvbuf = hub_malloc(MAX_RECV_BUF);
hub->sendbuf = hub_malloc(MAX_SEND_BUF);
if (!hub->recvbuf || !hub->sendbuf)
{
hub_free(hub->recvbuf);
hub_free(hub->sendbuf);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
return 0;
}
hub->chat_history = (struct linked_list*) list_create();
hub->logout_info = (struct linked_list*) list_create();
if (!hub->chat_history)
{
list_destroy(hub->chat_history);
list_destroy(hub->logout_info);
hub_free(hub->recvbuf);
hub_free(hub->sendbuf);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
return 0;
}
hub->status = hub_status_running;
g_hub = hub;
return hub;
}
void hub_shutdown_service(struct hub_info* hub)
{
LOG_TRACE("hub_shutdown_service()");
hub_log(log_trace, "hub_shutdown_service()");
event_queue_shutdown(hub->queue);
event_del(&hub->ev_accept);
@@ -581,15 +528,8 @@ void hub_shutdown_service(struct hub_info* hub)
uman_shutdown(hub);
hub->status = hub_status_stopped;
event_base_free(hub->evbase);
hub_free(hub->sendbuf);
hub_free(hub->recvbuf);
hub_chat_history_clear(hub);
list_destroy(hub->chat_history);
list_clear(hub->logout_info, &hub_free);
list_destroy(hub->logout_info);
hub_free(hub);
hub = 0;
g_hub = 0;
}
#define SERVER "" PRODUCT "/" VERSION ""
@@ -599,14 +539,14 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
int fd, ret;
char buf[MAX_RECV_BUF];
char* tmp;
char* server = adc_msg_escape(SERVER); /* FIXME: OOM */
hub->acl = acl;
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15 + strlen(server));
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15 + strlen(SERVER));
if (hub->command_info)
{
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, server);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, SERVER);
tmp = adc_msg_escape(hub->config->hub_name);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_NICK, tmp);
@@ -644,17 +584,13 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
}
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(server));
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(SERVER));
if (hub->command_banner)
{
tmp = adc_msg_escape("Powered by " SERVER);
adc_msg_add_argument(hub->command_banner, "000");
adc_msg_add_argument(hub->command_banner, tmp);
hub_free(tmp);
adc_msg_add_argument(hub->command_banner, "000 Powered\\sby\\s" SERVER);
}
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
hub_free(server);
}
@@ -675,7 +611,7 @@ void hub_free_variables(struct hub_info* hub)
*/
static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
{
struct hub_user* lookup = uman_get_user_by_nick(hub, nick);
struct user* lookup = uman_get_user_by_nick(hub, nick);
if (lookup)
{
return 1;
@@ -689,7 +625,7 @@ static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
*/
static inline int is_cid_in_use(struct hub_info* hub, const char* cid)
{
struct hub_user* lookup = uman_get_user_by_cid(hub, cid);
struct user* lookup = uman_get_user_by_cid(hub, cid);
if (lookup)
{
return 1;
@@ -714,7 +650,7 @@ static void set_status_code(enum msg_status_level level, int code, char buffer[4
* @param msg See enum status_message
* @param level See enum status_level
*/
void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_message msg, enum msg_status_level level)
void hub_send_status(struct hub_info* hub, struct user* user, enum status_message msg, enum msg_status_level level)
{
struct hub_config* cfg = hub->config;
struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
@@ -771,7 +707,7 @@ void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_me
adc_msg_add_argument(cmd, flag);
}
route_to_user(hub, user, cmd);
route_to_user(user, cmd);
adc_msg_free(cmd);
}
@@ -941,7 +877,7 @@ void hub_event_loop(struct hub_info* hub)
if (ret != 0)
{
LOG_DEBUG("event_base_loop returned: %d", (int) ret);
hub_log(log_debug, "event_base_loop returned: %d", (int) ret);
}
if (ret < 0)
@@ -951,70 +887,3 @@ void hub_event_loop(struct hub_info* hub)
}
while (hub->status == hub_status_running || hub->status == hub_status_disabled);
}
void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
{
struct event_data post;
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_DESTROY;
post.ptr = user;
event_queue_post(hub->queue, &post);
if (user->id.sid)
{
sid_free(hub->users->sids, user->id.sid);
}
}
void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason)
{
struct event_data post;
int need_notify = 0;
/* is user already being disconnected ? */
if (user_is_disconnecting(user))
{
return;
}
/* stop reading from user */
net_shutdown_r(user->net.connection.sd);
LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state);
need_notify = user_is_logged_in(user);
user->quit_reason = reason;
user_set_state(user, state_cleanup);
if (need_notify)
{
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_QUIT;
post.ptr = user;
event_queue_post(hub->queue, &post);
}
else
{
hub_schedule_destroy_user(hub, user);
}
}
void hub_logout_log(struct hub_info* hub, struct hub_user* user)
{
struct hub_logout_info* loginfo = hub_malloc_zero(sizeof(struct hub_logout_info));
if (!loginfo) return;
loginfo->time = time(NULL);
strcpy(loginfo->cid, user->id.cid);
strcpy(loginfo->nick, user->id.nick);
memcpy(&loginfo->addr, &user->net.ipaddr, sizeof(struct ip_addr_encap));
loginfo->reason = user->quit_reason;
list_append(hub->logout_info, loginfo);
while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log)
{
struct hub_logout_info* entry = list_get_first(hub->logout_info);
list_remove(hub->logout_info, entry);
hub_free(entry);
}
}

View File

@@ -79,15 +79,6 @@ struct hub_stats
size_t net_rx_total;
};
struct hub_logout_info
{
time_t time;
char cid[MAX_CID_LEN+1];
char nick[MAX_NICK_LEN+1];
struct ip_addr_encap addr;
enum user_quit_reason reason;
};
struct hub_info
{
int fd_tcp;
@@ -97,7 +88,7 @@ struct hub_info
struct event_queue* queue;
struct event_base* evbase;
struct hub_config* config;
struct hub_user_manager* users;
struct user_manager* users;
struct acl_handle* acl;
struct adc_message* command_info; /* The hub's INF command */
struct adc_message* command_support; /* The hub's SUP command */
@@ -105,12 +96,6 @@ struct hub_info
struct adc_message* command_banner; /* The default welcome message */
time_t tm_started;
int status;
char* recvbuf; /* Global receive buffer */
char* sendbuf; /* Global send buffer */
struct linked_list* chat_history; /* Chat history */
struct linked_list* logout_info; /* Log of people logging out. */
#ifdef SSL_SUPPORT
SSL_METHOD* ssl_method;
SSL_CTX* ssl_ctx;
@@ -125,97 +110,87 @@ struct hub_info
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* message, size_t length);
extern int hub_handle_message(struct hub_info* hub, struct user* u, const char* message, size_t length);
/**
* Handle protocol support/subscription messages received clients.
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
extern int hub_handle_support(struct hub_info* hub, struct user* u, struct adc_message* cmd);
/**
* Handle password messages received from clients.
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
extern int hub_handle_password(struct hub_info* hub, struct user* u, struct adc_message* cmd);
/**
* Handle chat messages received from clients.
* @return 0 on success, -1 on error.
*/
extern int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Add a chat message to the chat history
*/
extern void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd);
/**
* Clear the chat history.
*/
extern void hub_chat_history_clear(struct hub_info* hub);
extern int hub_handle_chat_message(struct hub_info* hub, struct user* u, struct adc_message* cmd);
/**
* Used internally by hub_handle_info
* @return 1 if nickname is OK, or 0 if nickname is not accepted.
*/
extern int hub_handle_info_check_nick(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
extern int hub_handle_info_check_nick(struct hub_info* hub, struct user* u, struct adc_message* cmd);
/**
* Used internally by hub_handle_info
* @return 1 if CID/PID is OK, or 0 if not valid.
*/
extern int hub_handle_info_check_cid(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
extern int hub_handle_info_check_cid(struct hub_info* hub, struct user* u, struct adc_message* cmd);
/**
* Send the support line for the hub to a particular user.
* Only used during the initial handshake.
*/
extern void hub_send_support(struct hub_info* hub, struct hub_user* u);
extern void hub_send_support(struct hub_info* hub, struct user* u);
/**
* Send a message assigning a SID for a user.
* This is only sent after hub_send_support() during initial handshake.
*/
extern void hub_send_sid(struct hub_info* hub, struct hub_user* u);
extern void hub_send_sid(struct hub_info* hub, struct user* u);
/**
* Send a 'ping' message to user.
*/
extern void hub_send_ping(struct hub_info* hub, struct hub_user* user);
extern void hub_send_ping(struct hub_info* hub, struct user* user);
/**
* Send a message containing hub information to a particular user.
* This is sent during user connection, but can safely be sent at any
* point later.
*/
extern void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u);
extern void hub_send_hubinfo(struct hub_info* hub, struct user* u);
/**
* Send handshake. This basically calls
* hub_send_support() and hub_send_sid()
*/
extern void hub_send_handshake(struct hub_info* hub, struct hub_user* u);
extern void hub_send_handshake(struct hub_info* hub, struct user* u);
/**
* Send a welcome message containing the message of the day to
* one particular user. This can be sent in any point in time.
*/
extern void hub_send_motd(struct hub_info* hub, struct hub_user* u);
extern void hub_send_motd(struct hub_info* hub, struct user* u);
/**
* Send a password challenge to a user.
* This is only used if the user tries to access the hub using a
* password protected nick name.
*/
extern void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u);
extern void hub_send_password_challenge(struct hub_info* hub, struct user* u);
/**
* Sends a status_message to a user.
*/
extern void hub_send_status(struct hub_info*, struct hub_user* user, enum status_message msg, enum msg_status_level level);
extern void hub_send_status(struct hub_info*, struct user* user, enum status_message msg, enum msg_status_level level);
/**
* Allocates memory, initializes the hub based on the configuration,
@@ -343,21 +318,6 @@ extern void hub_schedule_runslice(struct hub_info* hub);
*/
extern void hub_event_loop(struct hub_info* hub);
/**
* Schedule destroying a user.
*/
extern void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user);
/**
* Disconnect a user from the hub.
*/
extern void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason);
/**
* Log a user logging out.
*/
extern void hub_logout_log(struct hub_info* hub, struct hub_user* user);
#endif /* HAVE_UHUB_HUB_H */

122
src/hubevent.c Normal file
View File

@@ -0,0 +1,122 @@
/*
* 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/>.
*
*/
#include "uhub.h"
static void log_user_login(struct user* u)
{
const char* cred = get_user_credential_string(u->credentials);
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "LoginOK %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, cred, u->user_agent);
}
static void log_user_login_error(struct user* u, enum status_message msg)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
const char* message = hub_get_status_message_log(u->hub, msg);
hub_log(log_user, "LoginError %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message, u->user_agent);
}
static void log_user_logout(struct user* u, const char* message)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "Logout %s/%s %s \"%s\" (%s)", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message);
}
static void log_user_nick_change(struct user* u, const char* nick)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick);
}
/* Send MOTD, do logging etc */
void on_login_success(struct hub_info* hub, struct user* u)
{
struct timeval timeout = { TIMEOUT_IDLE, 0 };
/* Send user list of all existing users */
if (!uman_send_user_list(u))
return;
/* Mark as being in the normal state, and add user to the user list */
user_set_state(u, state_normal);
uman_add(hub, u);
/* Print log message */
log_user_login(u);
/* Announce new user to all connected users */
if (user_is_logged_in(u))
route_info_message(u);
/* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(hub, u);
/* reset to idle timeout */
if (u->ev_read)
event_add(u->ev_read, &timeout);
}
void on_login_failure(struct hub_info* hub, struct user* u, enum status_message msg)
{
log_user_login_error(u, msg);
hub_send_status(hub, u, msg, status_level_fatal);
user_disconnect(u, quit_logon_error);
}
void on_nick_change(struct hub_info* hub, struct user* u, const char* nick)
{
if (user_is_logged_in(u))
{
log_user_nick_change(u, nick);
}
}
void on_logout_user(struct hub_info* hub, struct user* user)
{
const char* reason = "";
/* These are used for logging purposes */
switch (user->quit_reason)
{
case quit_disconnected: reason = "disconnected"; break;
case quit_kicked: reason = "kicked"; break;
case quit_banned: reason = "banned"; break;
case quit_timeout: reason = "timeout"; break;
case quit_send_queue: reason = "send queue"; break;
case quit_memory_error: reason = "out of memory"; break;
case quit_socket_error: reason = "socket error"; break;
case quit_protocol_error: reason = "protocol error"; break;
case quit_logon_error: reason = "login error"; break;
case quit_hub_disabled: reason = "hub disabled"; break;
case quit_ghost_timeout: reason = "ghost"; break;
default:
if (hub->status == hub_status_shutdown)
reason = "hub shutdown";
else
reason = "unknown error";
break;
}
log_user_logout(user, reason);
user->quit_reason = 0;
}

View File

@@ -23,22 +23,22 @@
/**
* This event is triggered whenever a user successfully logs in to the hub.
*/
extern void on_login_success(struct hub_info* hub, struct hub_user* u);
extern void on_login_success(struct hub_info* hub, struct user* u);
/**
* This event is triggered whenever a user failed to log in to the hub.
*/
extern void on_login_failure(struct hub_info* hub, struct hub_user* u, enum status_message msg);
extern void on_login_failure(struct hub_info* hub, struct user* u, enum status_message msg);
/**
* This event is triggered whenever a previously logged in user leaves the hub.
*/
extern void on_logout_user(struct hub_info* hub, struct hub_user* u);
extern void on_logout_user(struct hub_info* hub, struct user* u);
/**
* This event is triggered whenever a user changes his/her nickname.
*/
extern void on_nick_change(struct hub_info* hub, struct hub_user* u, const char* nick);
extern void on_nick_change(struct hub_info* hub, struct user* u, const char* nick);
#endif /* HAVE_UHUB_HUB_EVENT_H */

View File

@@ -39,7 +39,9 @@ static void remove_server_restricted_flags(struct adc_message* cmd)
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_REFERER);
}
static int set_feature_cast_supports(struct hub_user* u, struct adc_message* cmd)
static int user_is_protected(struct user* user);
static int set_feature_cast_supports(struct user* u, struct adc_message* cmd)
{
char *it, *tmp;
@@ -87,7 +89,7 @@ static int check_hash_tiger(const char* cid, const char* pid)
/*
* FIXME: Only works for tiger hash. If a client doesnt support tiger we cannot let it in!
*/
static int check_cid(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_cid(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
size_t pos;
char* cid = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
@@ -148,7 +150,7 @@ static int check_cid(struct hub_info* hub, struct hub_user* user, struct adc_mes
}
static int check_required_login_flags(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_required_login_flags(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
int num = 0;
@@ -184,9 +186,9 @@ static int check_required_login_flags(struct hub_info* hub, struct hub_user* use
* remove any wrong address, and replace it with the correct one
* as seen by the hub.
*/
int check_network(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
int check_network(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
const char* address = ip_convert_to_string(&user->net.ipaddr);
const char* address = ip_convert_to_string(&user->ipaddr);
/* Check for NAT override address */
if (acl_is_ip_nat_override(hub->acl, address))
@@ -220,7 +222,7 @@ int check_network(struct hub_info* hub, struct hub_user* user, struct adc_messag
return 0;
}
void strip_network(struct hub_user* user, struct adc_message* cmd)
void strip_network(struct user* user, struct adc_message* cmd)
{
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_UDP_PORT);
@@ -274,7 +276,7 @@ static int nick_is_utf8(const char* nick)
}
static int check_nick(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_nick(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
char* nick;
char* tmp;
@@ -322,10 +324,10 @@ static int check_nick(struct hub_info* hub, struct hub_user* user, struct adc_me
}
static int check_logged_in(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_logged_in(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
struct hub_user* lookup1 = uman_get_user_by_nick(hub, user->id.nick);
struct hub_user* lookup2 = uman_get_user_by_cid(hub, user->id.cid);
struct user* lookup1 = uman_get_user_by_nick(hub, user->id.nick);
struct user* lookup2 = uman_get_user_by_cid(hub, user->id.cid);
if (lookup1 == user)
{
@@ -336,20 +338,20 @@ static int check_logged_in(struct hub_info* hub, struct hub_user* user, struct a
{
if (lookup1 == lookup2)
{
LOG_DEBUG("check_logged_in: exact same user is logged in: %s", user->id.nick);
hub_disconnect_user(hub, lookup1, quit_ghost_timeout);
hub_log(log_debug, "check_logged_in: exact same user is logged in: %s", user->id.nick);
user_disconnect(lookup1, quit_ghost_timeout);
return 0;
}
else
{
if (lookup1)
{
LOG_DEBUG("check_logged_in: nickname is in use: %s", user->id.nick);
hub_log(log_debug, "check_logged_in: nickname is in use: %s", user->id.nick);
return status_msg_inf_error_nick_taken;
}
else
{
LOG_DEBUG("check_logged_in: CID is in use: %s", user->id.cid);
hub_log(log_debug, "check_logged_in: CID is in use: %s", user->id.cid);
return status_msg_inf_error_cid_taken;
}
}
@@ -363,7 +365,7 @@ static int check_logged_in(struct hub_info* hub, struct hub_user* user, struct a
* But this is not something we want to do, and is deprecated in the ADC specification.
* One should rather look at capabilities/features.
*/
static int check_user_agent(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_user_agent(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
char* ua_encoded = 0;
char* ua = 0;
@@ -384,7 +386,7 @@ static int check_user_agent(struct hub_info* hub, struct hub_user* user, struct
}
static int check_acl(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_acl(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
if (acl_is_cid_banned(hub->acl, user->id.cid))
{
@@ -404,7 +406,7 @@ static int check_acl(struct hub_info* hub, struct hub_user* user, struct adc_mes
return 0;
}
static int check_limits(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int check_limits(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
char* arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SHARED_SIZE);
if (arg)
@@ -495,16 +497,16 @@ static int check_limits(struct hub_info* hub, struct hub_user* user, struct adc_
return status_msg_user_share_size_high;
}
if ((user->limits.hub_count_user > hub_get_max_hubs_user(hub) && hub_get_max_hubs_user(hub)) ||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(hub) && hub_get_max_hubs_reg(hub)) ||
(user->limits.hub_count_operator > hub_get_max_hubs_op(hub) && hub_get_max_hubs_op(hub)) ||
if ((user->limits.hub_count_user > hub_get_max_hubs_user(hub) && hub_get_max_hubs_user(hub)) ||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(hub) && hub_get_max_hubs_reg(hub)) ||
(user->limits.hub_count_operator > hub_get_max_hubs_op(hub) && hub_get_max_hubs_op(hub)) ||
(user->limits.hub_count_total > hub_get_max_hubs_total(hub) && hub_get_max_hubs_total(hub)))
{
return status_msg_user_hub_limit_high;
}
if ((user->limits.hub_count_user < hub_get_min_hubs_user(hub) && hub_get_min_hubs_user(hub)) ||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(hub) && hub_get_min_hubs_reg(hub)) ||
if ((user->limits.hub_count_user < hub_get_min_hubs_user(hub) && hub_get_min_hubs_user(hub)) ||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(hub) && hub_get_min_hubs_reg(hub)) ||
(user->limits.hub_count_operator < hub_get_min_hubs_op(hub) && hub_get_min_hubs_op(hub)))
{
return status_msg_user_hub_limit_low;
@@ -530,10 +532,10 @@ static int check_limits(struct hub_info* hub, struct hub_user* user, struct adc_
* If the hub is configured to allow only registered users and the user
* is not recognized this will return 1.
*/
static int set_credentials(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int set_credentials(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
int ret = 0;
struct hub_user_access_info* info = acl_get_access_info(hub->acl, user->id.nick);
struct user_access_info* info = acl_get_access_info(hub->acl, user->id.nick);
if (info)
{
@@ -582,8 +584,49 @@ static int set_credentials(struct hub_info* hub, struct hub_user* user, struct a
}
/**
* Determines if a user is to be let into the hub even if the hub is "full".
*/
static int user_is_protected(struct user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
static int check_is_hub_full(struct hub_info* hub, struct hub_user* user)
/**
* Returns 1 if a user is registered.
* Only registered users will be let in if the hub is configured for registered
* users only.
*/
static int user_is_registered(struct user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_user:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
static int check_is_hub_full(struct hub_info* hub, struct user* user)
{
/*
* If hub is full, don't let users in, but we still want to allow
@@ -597,7 +640,7 @@ static int check_is_hub_full(struct hub_info* hub, struct hub_user* user)
}
static int check_registered_users_only(struct hub_info* hub, struct hub_user* user)
static int check_registered_users_only(struct hub_info* hub, struct user* user)
{
if (hub->config->registered_users_only && !user_is_registered(user))
{
@@ -606,7 +649,7 @@ static int check_registered_users_only(struct hub_info* hub, struct hub_user* us
return 0;
}
static int hub_handle_info_common(struct hub_user* user, struct adc_message* cmd)
static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
{
/* Remove server restricted flags */
remove_server_restricted_flags(cmd);
@@ -617,7 +660,7 @@ static int hub_handle_info_common(struct hub_user* user, struct adc_message* cmd
return 0;
}
static int hub_handle_info_low_bandwidth(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
static int hub_handle_info_low_bandwidth(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
if (hub->config->low_bandwidth_mode)
{
@@ -645,7 +688,7 @@ static int hub_handle_info_low_bandwidth(struct hub_info* hub, struct hub_user*
return ret; \
} while(0)
int hub_perform_login_checks(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
int hub_perform_login_checks(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
/* Make syntax checks. */
INF_CHECK(check_required_login_flags, hub, user, cmd);
@@ -659,22 +702,17 @@ int hub_perform_login_checks(struct hub_info* hub, struct hub_user* user, struct
return 0;
}
/**
* Perform additional INF checks used at time of login.
*
* @return 0 if success, <0 if error, >0 if authentication needed.
*/
int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
int hub_handle_info_login(struct hub_info* hub, struct user* user, struct adc_message* cmd)
{
int code = 0;
int need_auth = 0;
INF_CHECK(hub_perform_login_checks, hub, user, cmd);
/* Private ID must never be broadcasted - drop it! */
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
code = set_credentials(hub, user, cmd);
/* FIXME: This needs some cleaning up */
need_auth = set_credentials(hub, user, cmd);
/* Note: this must be done *after* set_credentials. */
if (check_is_hub_full(hub, user))
@@ -695,7 +733,7 @@ int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct ad
/* Set initial user info */
user_set_info(user, cmd);
return code;
return need_auth;
}
/*
@@ -711,7 +749,7 @@ int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct ad
* - CID/PID (valid, not taken, etc).
* - IP addresses (IPv4 and IPv6)
*/
int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct adc_message* cmd_unmodified)
int hub_handle_info(struct hub_info* hub, struct user* user, const struct adc_message* cmd_unmodified)
{
struct adc_message* cmd = adc_msg_copy(cmd_unmodified);
if (!cmd) return -1; /* OOM */
@@ -767,7 +805,7 @@ int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct ad
*/
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK))
{
#ifdef ALLOW_CHANGE_NICK
#if ALLOW_CHANGE_NICK
if (!check_nick(hub, user, cmd))
#endif
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK);
@@ -782,7 +820,7 @@ int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct ad
if (!adc_msg_is_empty(cmd))
{
route_message(hub, user, cmd);
route_message(user, cmd);
}
adc_msg_free(cmd);

View File

@@ -47,7 +47,7 @@ enum nick_status
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_info(struct hub_info* hub, struct hub_user* u, const struct adc_message* cmd);
extern int hub_handle_info(struct hub_info* hub, struct user* u, const struct adc_message* cmd);
#endif /* HAVE_UHUB_INF_PARSER_H */

View File

@@ -19,6 +19,7 @@
#include "uhub.h"
int ip_is_valid_ipv4(const char* address)
{
int i = 0; /* address index */
@@ -146,7 +147,7 @@ int ip_convert_address(const char* text_address, int port, struct sockaddr* addr
addr6.sin6_port = htons(port);
if (net_string_to_address(AF_INET6, taddr, &addr6.sin6_addr) <= 0)
{
LOG_ERROR("Unable to convert socket address (ipv6)");
hub_log(log_fatal, "Unable to convert socket address (ipv6)");
return 0;
}
@@ -162,7 +163,7 @@ int ip_convert_address(const char* text_address, int port, struct sockaddr* addr
addr4.sin_port = htons(port);
if (net_string_to_address(AF_INET, taddr, &addr4.sin_addr) <= 0)
{
LOG_ERROR("Unable to convert socket address (ipv4)");
hub_log(log_fatal, "Unable to convert socket address (ipv4)");
return 0;
}
memcpy(addr, &addr4, sockaddr_size);
@@ -218,7 +219,7 @@ int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result)
#ifdef IP_CALC_DEBUG
char* r_str = hub_strdup(ip_convert_to_string(result));
LOG_DUMP("Created left mask: %s", r_str);
hub_log(log_debug, "Created left mask: %s", r_str);
hub_free(r_str);
#endif
@@ -271,7 +272,7 @@ int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result)
#ifdef IP_CALC_DEBUG
char* r_str = hub_strdup(ip_convert_to_string(result));
LOG_DUMP("Created right mask: %s", r_str);
hub_log(log_debug, "Created right mask: %s", r_str);
hub_free(r_str);
#endif
@@ -404,7 +405,7 @@ int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b)
#ifdef IP_CALC_DEBUG
char* a_str = hub_strdup(ip_convert_to_string(a));
char* b_str = hub_strdup(ip_convert_to_string(b));
LOG_DUMP("Comparing IPs '%s' AND '%s' => %d", a_str, b_str, ret);
hub_log(log_debug, "Comparing IPs '%s' AND '%s' => %d", a_str, b_str, ret);
hub_free(a_str);
hub_free(b_str);
#endif
@@ -412,80 +413,13 @@ int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b)
return ret;
}
static int check_ip_mask(const char* text_addr, int bits, struct ip_range* range)
{
if (ip_is_valid_ipv4(text_addr) || ip_is_valid_ipv6(text_addr))
{
struct ip_addr_encap addr;
struct ip_addr_encap mask1;
struct ip_addr_encap mask2;
int af = ip_convert_to_binary(text_addr, &addr); /* 192.168.1.2 */
int maxbits = (af == AF_INET6 ? 128 : 32);
bits = MIN(MAX(bits, 0), maxbits);
ip_mask_create_left(af, bits, &mask1); /* 255.255.255.0 */
ip_mask_create_right(af, maxbits - bits, &mask2); /* 0.0.0.255 */
ip_mask_apply_AND(&addr, &mask1, &range->lo); /* 192.168.1.0 */
ip_mask_apply_OR(&range->lo, &mask2, &range->hi); /* 192.168.1.255 */
return 1;
}
return 0;
}
static int check_ip_range(const char* lo, const char* hi, struct ip_range* range)
{
int ret1, ret2;
if ((ip_is_valid_ipv4(lo) && ip_is_valid_ipv4(hi)) || (ip_is_valid_ipv6(lo) && ip_is_valid_ipv6(hi)))
{
ret1 = ip_convert_to_binary(lo, &range->lo);
ret2 = ip_convert_to_binary(hi, &range->hi);
if (ret1 == -1 || ret2 == -1 || ret1 != ret2)
{
return 0;
}
return 1;
}
return 0;
}
int ip_convert_address_to_range(const char* address, struct ip_range* range)
{
int ret = 0;
char* addr = 0;
if (!address || !range)
return 0;
const char* split = strrchr(address, '/');
if (split)
{
int mask = uhub_atoi(split+1);
if (mask == 0 && split[1] != '0') return 0;
addr = hub_strndup(address, split - address);
ret = check_ip_mask(addr, mask, range);
hub_free(addr);
return ret;
}
split = strrchr(address, '-');
if (split)
{
addr = hub_strndup(address, split - address);
ret = check_ip_range(addr, split+1, range);
hub_free(addr);
return ret;
}
if (ip_is_valid_ipv4(address) || ip_is_valid_ipv6(address))
{
if (ip_convert_to_binary(address, &range->lo) == -1)
return 0;
memcpy(&range->hi, &range->lo, sizeof(struct ip_addr_encap));
return 1;
}
return 0;
}
int ip_in_range(struct ip_addr_encap* addr, struct ip_range* range)
{
return (addr->af == range->lo.af && ip_compare(&range->lo, addr) <= 0 && ip_compare(addr, &range->hi) <= 0);
}

View File

@@ -33,57 +33,26 @@ struct ip_addr_encap {
} internal_ip_data;
};
struct ip_range
{
struct ip_addr_encap lo;
struct ip_addr_encap hi;
};
extern int ip_convert_to_binary(const char* text_addr, struct ip_addr_encap* raw);
extern const char* ip_convert_to_string(struct ip_addr_encap* raw);
/**
* Convert a string on the form:
* ip-ip or ip/mask to an iprange.
*
* Note: both IPv4 and IPv6 addresses are valid, but if a range is given
* both addresses must be of the same address family.
*
* Valid examples of address
* IPv4:
* 192.168.2.1
* 192.168.0.0/16
* 192.168.0.0-192.168.255.255
*
* IPv6:
* 2001:4860:A005::68
* 2001:4860:A005::0/80
* 2001:4860:A005::0-2001:4860:A005:ffff:ffff:ffff:ffff:ffff
*
* @return 0 if invalid, 1 if OK
*/
extern int ip_convert_address_to_range(const char* address, struct ip_range* range);
/**
* @return 1 if addr is inside range, 0 otherwise
*/
extern int ip_in_range(struct ip_addr_encap* addr, struct ip_range* range);
/**
/*
* @return 1 if address is a valid IPv4 address in text notation
* 0 if invalid
*/
extern int ip_is_valid_ipv4(const char* address);
/**
/*
* @return 1 if address is a valid IPv6 address in text notation
* 0 if invalid
*/
extern int ip_is_valid_ipv6(const char* address);
/**
/*
* This function converts an IP address in text_address to a binary
* struct sockaddr.
* This will auto-detect if the IP-address is IPv6 (and that is supported),
@@ -97,6 +66,7 @@ extern int ip_is_valid_ipv6(const char* address);
*/
extern int ip_convert_address(const char* text_address, int port, struct sockaddr* addr, socklen_t* addr_len);
extern int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result);
extern int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result);

View File

@@ -33,31 +33,6 @@ enum log_verbosity {
log_protocol = 9,
};
#define LOG_FATAL(format, ...) hub_log(log_fatal, format, ## __VA_ARGS__)
#define LOG_ERROR(format, ...) hub_log(log_error, format, ## __VA_ARGS__)
#define LOG_WARN(format, ...) hub_log(log_warning, format, ## __VA_ARGS__)
#define LOG_USER(format, ...) hub_log(log_user, format, ## __VA_ARGS__)
#define LOG_INFO(format, ...) hub_log(log_info, format, ## __VA_ARGS__)
#ifdef DEBUG
# define LOG_DEBUG(format, ...) hub_log(log_debug, format, ## __VA_ARGS__)
# define LOG_TRACE(format, ...) hub_log(log_trace, format, ## __VA_ARGS__)
#else
# define LOG_DEBUG(format, ...) do { } while(0)
# define LOG_TRACE(format, ...) do { } while(0)
#endif
#ifdef LOWLEVEL_DEBUG
# define LOG_DUMP(format, ...) hub_log(log_dump, format, ## __VA_ARGS__)
# define LOG_MEMORY(format, ...) hub_log(log_memory, format, ## __VA_ARGS__)
# define LOG_PROTO(format, ...) hub_log(log_protocol, format, ## __VA_ARGS__)
#else
# define LOG_DUMP(format, ...) do { } while(0)
# define LOG_MEMORY(format, ...) do { } while(0)
# define LOG_PROTO(format, ...) do { } while(0)
#endif
/**
* Specify a minimum log verbosity for what messages should
* be printed in the log.

View File

@@ -29,7 +29,6 @@ static const char* arg_uid = 0;
static const char* arg_gid = 0;
static const char* arg_config = 0;
static const char* arg_log = 0;
static const char* arg_pid = 0;
static int arg_log_syslog = 0;
@@ -42,12 +41,12 @@ void hub_handle_signal(int fd, short events, void* arg)
switch (signal)
{
case SIGINT:
LOG_INFO("Interrupted. Shutting down...");
hub_log(log_info, "Interrupted. Shutting down...");
hub->status = hub_status_shutdown;
break;
case SIGTERM:
LOG_INFO("Terminated. Shutting down...");
hub_log(log_info, "Terminated. Shutting down...");
hub->status = hub_status_shutdown;
break;
@@ -59,7 +58,7 @@ void hub_handle_signal(int fd, short events, void* arg)
break;
default:
LOG_TRACE("hub_handle_signal(): caught unknown signal: %d", signal);
hub_log(log_trace, "hub_handle_signal(): caught unknown signal: %d", signal);
hub->status = hub_status_shutdown;
break;
}
@@ -84,9 +83,9 @@ void setup_signal_handlers(struct hub_info* hub)
event_base_set(hub->evbase, &signal_events[i]);
if (signal_add(&signal_events[i], NULL))
{
LOG_ERROR("Error setting signal handler %d", signals[i]);
hub_log(log_error, "Error setting signal handler %d", signals[i]);
}
}
}
}
void shutdown_signal_handlers(struct hub_info* hub)
@@ -95,7 +94,7 @@ void shutdown_signal_handlers(struct hub_info* hub)
for (i = 0; signals[i]; i++)
{
signal_del(&signal_events[i]);
}
}
}
#endif /* WIN32 */
@@ -114,8 +113,8 @@ int main_loop()
{
if (hub)
{
LOG_INFO("Reloading configuration files...");
LOG_DEBUG("Hub status: %d", (int) hub->status);
hub_log(log_info, "Reloading configuration files...");
hub_log(log_debug, "Hub status: %d", (int) hub->status);
}
if (read_config(arg_config, &configuration, !arg_have_config) == -1)
@@ -158,7 +157,7 @@ int main_loop()
hub_shutdown_service(hub);
}
net_destroy();
net_shutdown();
hub_log_shutdown();
return 0;
}
@@ -191,7 +190,7 @@ int check_configuration(int dump)
void print_version()
{
fprintf(stdout, "" PRODUCT " " VERSION "\n");
fprintf(stdout, "" PRODUCT " " VERSION " " PRODUCT_TITLE "\n");
fprintf(stdout, "Copyright (C) 2007-2009, Jan Vidar Krey <janvidar@extatic.org>\n"
"This is free software with ABSOLUTELY NO WARRANTY.\n\n");
exit(0);
@@ -216,7 +215,6 @@ void print_usage(char* program)
#ifndef WIN32
" -u <user> Run as given user\n"
" -g <group> Run with given group permissions\n"
" -p <file> Store pid in file (process id)\n"
#endif
" -V Show version number.\n"
);
@@ -228,7 +226,7 @@ void print_usage(char* program)
void parse_command_line(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "vqfc:l:hu:g:VCsSLp:")) != -1)
while ((opt = getopt(argc, argv, "vqfc:l:hu:g:VCsSL")) != -1)
{
switch (opt)
{
@@ -288,10 +286,6 @@ void parse_command_line(int argc, char** argv)
arg_gid = optarg;
break;
case 'p':
arg_pid = optarg;
break;
default:
print_usage(argv[0]);
break;
@@ -335,15 +329,15 @@ int drop_privileges()
if (!ret)
{
LOG_FATAL("Unable to determine group id, check group name.");
hub_log(log_fatal, "Unable to determine group id, check group name.");
return -1;
}
LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid);
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
ret = setgid(perm_gid);
if (ret == -1)
{
LOG_FATAL("Unable to change group id, permission denied.");
hub_log(log_fatal, "Unable to change group id, permission denied.");
return -1;
}
gid_ok = 1;
@@ -368,58 +362,31 @@ int drop_privileges()
if (!ret)
{
LOG_FATAL("Unable to determine user id, check user name.");
hub_log(log_fatal, "Unable to determine user id, check user name.");
return -1;
}
if (!gid_ok) {
LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid);
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
ret = setgid(perm_gid);
if (ret == -1)
{
LOG_FATAL("Unable to change group id, permission denied.");
hub_log(log_fatal, "Unable to change group id, permission denied.");
return -1;
}
}
LOG_TRACE("Setting user id %d (%s)", (int) perm_uid, arg_uid);
hub_log(log_trace, "Setting user id %d (%s)", (int) perm_uid, arg_uid);
ret = setuid(perm_uid);
if (ret == -1)
{
LOG_FATAL("Unable to change user id, permission denied.");
hub_log(log_fatal, "Unable to change user id, permission denied.");
return -1;
}
}
return 0;
}
int pidfile_create()
{
if (arg_pid)
{
FILE* pidfile = fopen(arg_pid, "w");
if (!pidfile)
{
LOG_FATAL("Unable to write pid file: %s\n", arg_pid);
return -1;
}
fprintf(pidfile, "%d", (int) getpid());
fclose(pidfile);
}
return 0;
}
int pidfile_destroy()
{
if (arg_pid)
{
return unlink(arg_pid);
}
return 0;
}
#endif /* WIN32 */
@@ -440,40 +407,26 @@ int main(int argc, char** argv)
ret = fork();
if (ret == -1)
{
LOG_FATAL("Unable to fork to background!");
hub_log(log_fatal, "Unable to fork to background!");
return -1;
}
else if (ret == 0)
{
/* child process - detatch from TTY */
fclose(stdin);
fclose(stdout);
fclose(stderr);
close(0);
close(1);
close(2);
/* child process */
}
else
{
/* parent process */
LOG_DEBUG("Forked to background\n");
hub_log(log_debug, "Forked to background\n");
return 0;
}
}
if (pidfile_create() == -1)
return -1;
if (drop_privileges() == -1)
return -1;
#endif /* WIN32 */
ret = main_loop();
#ifndef WIN32
pidfile_destroy();
#endif
return ret;
}

View File

@@ -47,7 +47,7 @@ void internal_debug_print_leaks()
size_t n = 0;
size_t leak = 0;
size_t count = 0;
LOG_MEMORY("--- exit (allocs: %d, size: %zu) ---", hub_alloc_count, hub_alloc_size);
hub_log(log_memory, "--- exit (allocs: %d, size: %zu) ---", hub_alloc_count, hub_alloc_size);
for (; n < UHUB_MAX_ALLOCS; n++)
{
@@ -55,11 +55,11 @@ void internal_debug_print_leaks()
{
leak += hub_allocs[n].size;
count++;
LOG_MEMORY("leak %p size: %zu (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2);
hub_log(log_memory, "leak %p size: %zu (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2);
}
}
LOG_MEMORY("--- done (allocs: %d, size: %zu, peak: %d/%zu, oom: %zu) ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom);
hub_log(log_memory, "--- done (allocs: %d, size: %zu, peak: %d/%zu, oom: %zu) ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom);
}
#endif /* REALTIME_MALLOC_TRACKING */
@@ -73,7 +73,7 @@ void* internal_debug_mem_malloc(size_t size, const char* where)
/* Make sure the malloc info struct is initialized */
if (!hub_alloc_count)
{
LOG_MEMORY("--- start ---");
hub_log(log_memory, "--- start ---");
for (n = 0; n < UHUB_MAX_ALLOCS; n++)
{
hub_allocs[n].ptr = 0;
@@ -107,14 +107,14 @@ void* internal_debug_mem_malloc(size_t size, const char* where)
hub_alloc_peak_count = MAX(hub_alloc_count, hub_alloc_peak_count);
hub_alloc_peak_size = MAX(hub_alloc_size, hub_alloc_peak_size);
LOG_MEMORY("%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: %zu}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size);
hub_log(log_memory, "%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: %zu}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size);
break;
}
}
}
else
{
LOG_MEMORY("%s *** OOM for %d bytes", where, size);
hub_log(log_memory, "%s *** OOM for %d bytes", where, size);
hub_alloc_oom++;
return 0;
}
@@ -141,7 +141,7 @@ void internal_debug_mem_free(void* ptr)
hub_allocs[n].size = 0;
hub_allocs[n].stack1 = 0;
hub_allocs[n].stack2 = 0;
LOG_MEMORY("free %p (bt: %p %p) {allocs: %d, size: %zu}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
hub_log(log_memory, "free %p (bt: %p %p) {allocs: %d, size: %zu}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
malloc_slot = n;
free(ptr);
return;
@@ -150,7 +150,7 @@ void internal_debug_mem_free(void* ptr)
malloc_slot = -1;
abort();
LOG_MEMORY("free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
hub_log(log_memory, "free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
#else
free(ptr);
#endif /* REALTIME_MALLOC_TRACKING */

View File

@@ -235,7 +235,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
}
struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* line, size_t length)
struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_t length)
{
struct adc_message* command = adc_msg_parse(line, length);
@@ -244,7 +244,6 @@ struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* line, s
if (command->source && (!u || command->source != u->id.sid))
{
LOG_DEBUG("Command does not match user's SID (command->source=%d, user->id.sid=%d)", command->source, (u ? u->id.sid : 0));
adc_msg_free(command);
return 0;
}
@@ -268,7 +267,7 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
if (!is_printable_utf8(line, length))
{
LOG_DEBUG("Dropped message with non-printable UTF-8 characters.");
hub_log(log_debug, "Dropped message with non-printable UTF-8 characters.");
hub_free(command);
return NULL;
}
@@ -520,6 +519,7 @@ int adc_msg_remove_named_argument(struct adc_message* cmd, const char prefix_[2]
{
temp_len = &end[0] - &start[0]; // strlen(start);
/* hub_log(log_trace, " length=%d", (int) (temp_len)); */
endlen = strlen(end);
memmove(start, end, endlen);

View File

@@ -20,7 +20,7 @@
#ifndef HAVE_UHUB_COMMAND_H
#define HAVE_UHUB_COMMAND_H
struct hub_user;
struct user;
struct adc_message
{
@@ -70,7 +70,7 @@ extern struct adc_message* adc_msg_copy(const struct adc_message* cmd);
* The message is only considered valid if the user who sent it
* is the rightful origin of the message.
*/
extern struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* string, size_t length);
extern struct adc_message* adc_msg_parse_verify(struct user* u, const char* string, size_t length);
/**
* This will parse 'string' and return it as a adc_message struct, or

View File

@@ -179,26 +179,26 @@ int file_read_lines(const char* file, void* data, file_line_handler_t handler)
memset(buf, 0, MAX_RECV_BUF);
LOG_TRACE("Opening file %s for line reading.", file);
hub_log(log_trace, "Opening file %s for line reading.", file);
fd = open(file, 0);
if (fd == -1)
{
LOG_ERROR("Unable to open file %s: %s", file, strerror(errno));
hub_log(log_error, "Unable to open file %s: %s", file, strerror(errno));
return -2;
}
ret = read(fd, buf, MAX_RECV_BUF);
if (ret < 0)
{
LOG_ERROR("Unable to read from file %s: %s", file, strerror(errno));
hub_log(log_error, "Unable to read from file %s: %s", file, strerror(errno));
close(fd);
return -1;
}
else if (ret == 0)
{
close(fd);
LOG_WARN("File is empty.");
hub_log(log_warning, "File is empty.");
return 0;
}
else
@@ -212,7 +212,7 @@ int file_read_lines(const char* file, void* data, file_line_handler_t handler)
pos[0] = '\0';
if (*start)
{
LOG_DUMP("Line: %s", start);
hub_log(log_dump, "Line: %s", start);
if (handler(start, line_count+1, data) < 0)
return -1;
}
@@ -223,7 +223,7 @@ int file_read_lines(const char* file, void* data, file_line_handler_t handler)
if (*start)
{
buf[strlen(start)] = 0;
LOG_DUMP("Line: %s", start);
hub_log(log_dump, "Line: %s", start);
if (handler(start, line_count+1, data) < 0)
return -1;
}
@@ -319,52 +319,4 @@ void* memmem(const void *haystack, size_t haystacklen, const void *needle, size_
}
#endif
int split_string(const char* string, const char* split, struct linked_list* list, int allow_empty)
{
char* tmp1, *tmp2;
int n = 0;
if (!string || !*string || !split || !*split || !list)
return -1;
for (;;)
{
tmp1 = strstr(string, split);
if (tmp1) tmp2 = hub_strndup(string, tmp1 - string);
else tmp2 = hub_strdup(string);
if (!tmp2)
{
list_clear(list, &hub_free);
return -1;
}
if (*tmp2 || allow_empty)
{
/* store in list */
list_append(list, tmp2);
n++;
}
else
{
/* ignore element */
hub_free(tmp2);
}
if (!tmp1) break; /* last element found */
string = tmp1;
string += strlen(split);
}
return n;
}
const char* get_timestamp(time_t now)
{
static char ts[32] = {0, };
struct tm* t = localtime(&now);
sprintf(ts, "[%02d:%02d]", t->tm_hour, t->tm_min);
return ts;
}

View File

@@ -22,8 +22,6 @@
typedef int (*file_line_handler_t)(char* line, int line_number, void* data);
extern const char* get_timestamp(time_t time);
extern int is_num(char c);
extern int is_space(char c);
extern int is_white_space(char c);
@@ -36,6 +34,7 @@ extern char* strip_white_space(char* string);
extern int file_read_lines(const char* file, void* data, file_line_handler_t handler);
extern const char* uhub_itoa(int val);
extern const char* uhub_ulltoa(uint64_t val);
@@ -54,13 +53,6 @@ extern char* strndup(const char* string, size_t n);
void* memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
#endif
/**
* Split the string based on split, and place the different parts into list.
* @return the number of items in the list after split, or -1 if an error occured.
*/
struct linked_list;
extern int split_string(const char* string, const char* split, struct linked_list* list, int allow_empty);
#endif /* HAVE_UHUB_MISC_H */

319
src/netevent.c Normal file
View File

@@ -0,0 +1,319 @@
/*
* 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/>.
*
*/
#include "uhub.h"
void net_on_read(int fd, short ev, void *arg)
{
static char buf[MAX_RECV_BUF];
struct user* user = (struct user*) arg;
char* pos;
size_t offset;
size_t buflen;
ssize_t size;
int more = 1;
int flag_close = 0;
hub_log(log_trace, "net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg);
if (ev == EV_TIMEOUT)
{
more = 0;
if (user_is_connecting(user))
{
flag_close = quit_timeout;
}
else
{
// FIXME: hub is not neccesarily set!
// hub_send_ping(hub, user);
}
}
while (more)
{
offset = 0;
if (user->recv_buf)
{
memcpy(buf, user->recv_buf, user->recv_buf_offset);
offset = user->recv_buf_offset;
}
size = net_recv(fd, &buf[offset], MAX_RECV_BUF - offset, 0);
if (size == -1)
{
if (net_error() != EWOULDBLOCK)
flag_close = quit_socket_error;
break;
}
else if (size == 0)
{
flag_close = quit_disconnected;
break;
}
else
{
buflen = offset + size;
ssize_t handled = 0;
while ((pos = memchr(&buf[handled], '\n', (buflen - handled))))
{
pos[0] = '\0';
size_t msglen = &pos[0] - &buf[handled];
if (user_flag_get(user, flag_maxbuf))
{
user_flag_unset(user, flag_maxbuf);
}
else
{
if (msglen < user->hub->config->max_recv_buffer)
{
// FIXME: hub is not set????
if (hub_handle_message(user->hub, user, &buf[handled], msglen) == -1)
{
flag_close = quit_protocol_error;
more = 0;
break;
}
}
}
handled += msglen;
handled++;
}
if (handled == 0 && user_flag_get(user, flag_maxbuf))
handled = buflen;
if (!more)
break;
if (handled < buflen)
{
if ((buflen - handled) > user->hub->config->max_recv_buffer)
{
user_flag_set(user, flag_maxbuf);
hub_free(user->recv_buf);
user->recv_buf = 0;
user->recv_buf_offset = 0;
}
else
{
if (!user->recv_buf)
user->recv_buf = hub_malloc(user->hub->config->max_recv_buffer);
if (user->recv_buf)
{
memcpy(user->recv_buf, &buf[handled], buflen - handled);
user->recv_buf_offset = buflen - handled;
}
else
{
flag_close = quit_memory_error;
break;
}
}
}
else
{
if (user->recv_buf)
{
hub_free(user->recv_buf);
user->recv_buf = 0;
user->recv_buf_offset = 0;
}
}
}
}
if (flag_close)
{
user_disconnect(user, flag_close);
return;
}
if (user_is_logged_in(user))
{
if (user->ev_read)
{
struct timeval timeout = { TIMEOUT_IDLE, 0 };
event_add(user->ev_read, &timeout);
}
}
else if (user_is_connecting(user))
{
if (user->ev_read)
{
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
event_add(user->ev_read, &timeout);
}
}
}
void net_on_write(int fd, short ev, void *arg)
{
struct user* user = (struct user*) arg;
struct adc_message* msg;
int ret;
int length;
int close_flag = 0;
msg = list_get_first(user->send_queue);
while (msg)
{
length = msg->length - user->send_queue_offset;
ret = net_send(user->sd, &msg->cache[user->send_queue_offset], length, UHUB_SEND_SIGNAL);
if (ret == 0 || (ret == -1 && net_error() == EWOULDBLOCK))
{
close_flag = 0;
break;
}
else if (ret > 0)
{
user->tm_last_write = time(NULL);
if (ret == length)
{
#ifdef DEBUG_SENDQ
hub_log(log_error, "SENDQ: sent=%d bytes/%d (all), send_queue_size=%d, offset=%d", ret, (int) msg->length, user->send_queue_size, user->send_queue_offset);
#endif
user->send_queue_size -= ret;
user->send_queue_offset = 0;
#ifdef DEBUG_SENDQ
if ((user->send_queue_size < 0) || (user->send_queue_offset < 0))
{
hub_log(log_error, "INVALID: send_queue_size=%d, send_queue_offset=%d", user->send_queue_size, user->send_queue_offset);
}
#endif
list_remove(user->send_queue, msg);
if (user_flag_get(user, flag_user_list) && (msg == user->info || user->send_queue_size == 0))
{
user_flag_unset(user, flag_user_list);
}
adc_msg_free(msg);
msg = 0;
if (user->send_queue_size == 0)
break;
}
else
{
#ifdef DEBUG_SENDQ
hub_log(log_error, "SENDQ: sent=%d bytes/%d (part), send_queue_size=%d, offset=%d", ret, (int) msg->length, user->send_queue_size, user->send_queue_offset);
#endif
user->send_queue_size -= ret;
user->send_queue_offset += ret;
#ifdef DEBUG_SENDQ
if ((user->send_queue_size < 0) || (user->send_queue_offset < 0) || (user->send_queue_offset > msg->length))
{
hub_log(log_error, "INVALID: send_queue_size=%d, send_queue_offset=%d", user->send_queue_size, user->send_queue_offset);
}
#endif
break;
}
}
else
{
close_flag = quit_socket_error;
break;
}
msg = list_get_first(user->send_queue);
}
if (close_flag)
{
user_disconnect(user, close_flag);
}
else
{
if (user->send_queue_size > 0 && user->ev_write)
event_add(user->ev_write, NULL);
}
}
void net_on_accept(int server_fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct user* user = 0;
struct ip_addr_encap ipaddr;
const char* addr;
struct timeval timeout = { TIMEOUT_CONNECTED, 0 };
for (;;)
{
int fd = net_accept(server_fd, &ipaddr);
if (fd == -1)
{
if (net_error() == EWOULDBLOCK)
{
break;
}
else
{
hub_log(log_error, "Accept error: %d %s", net_error(), strerror(net_error()));
break;
}
}
addr = ip_convert_to_string(&ipaddr);
/* FIXME: Should have a plugin log this */
hub_log(log_trace, "Got connection from %s", addr);
/* FIXME: A plugin should perform this check: is IP banned? */
if (acl_is_ip_banned(hub->acl, addr))
{
hub_log(log_info, "Denied [%s] (IP banned)", addr);
net_close(fd);
continue;
}
user = user_create(hub, fd);
if (!user)
{
hub_log(log_error, "Unable to create user after socket accepted. Out of memory?");
net_close(fd);
break;
}
/* Store IP address in user object */
memcpy(&user->ipaddr, &ipaddr, sizeof(ipaddr));
net_set_nonblocking(fd, 1);
net_set_nosigpipe(fd, 1);
event_set(user->ev_read, fd, EV_READ | EV_PERSIST, net_on_read, user);
event_set(user->ev_write, fd, EV_WRITE, net_on_write, user);
event_base_set(hub->evbase, user->ev_read);
event_base_set(hub->evbase, user->ev_write);
event_add(user->ev_read, &timeout);
}
}

View File

@@ -20,16 +20,25 @@
#ifndef HAVE_UHUB_NET_EVENT_H
#define HAVE_UHUB_NET_EVENT_H
/**
* Network callback for reading data from a socket.
*/
extern void net_on_read(int fd, short ev, void *arg);
/**
* Network callback for writing data to a socket.
*/
extern void net_on_write(int fd, short ev, void *arg);
/**
* Network callback for timers.
*/
extern void net_on_read_timeout(int fd, short ev, void* arg);
/**
* Network callback to accept incoming connections.
*/
extern void net_on_accept(int fd, short ev, void *arg);
extern void net_event(int fd, short ev, void *arg);
extern int handle_net_read(struct hub_user* user);
extern int handle_net_write(struct hub_user* user);
#endif /* HAVE_UHUB_NET_EVENT_H */

326
src/network-epoll.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007, 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 HAVE_EPOLL
// #define DEBUG_EPOLL
static struct epoll_event* events = 0;
static int epfd = -1;
#ifdef DEBUG_EPOLL
static void dump_listeners()
{
int i;
struct net_event_listener* listener;
hub_log(log_dump, "listeners: number=%d", num_connections);
for (i = 0; i < num_connections; i++)
{
listener = &listeners[i];
if (listener)
{
if (listener->fd != -1)
{
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d fd=%d, ptr=%p", i, num_connections, listeners->fd, listeners);
}
else
{
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d (unused)", i, num_connections);
}
listener = 0;
}
}
getc(stdin);
}
#endif
static void set_poll_events(struct epoll_event* handle, short trigger)
{
memset(handle, 0, sizeof(struct epoll_event));
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
handle->events |= EPOLLIN;
if (trigger & evt_write)
handle->events |= EPOLLOUT;
if (trigger & evt_urgent)
handle->events |= EPOLLPRI;
#ifdef EPOLLRDHUP
if (triggers & evt_close)
handle->events |= EPOLLRDHUP;
#endif
}
static short get_poll_events(struct epoll_event* handle)
{
short trig = handle->events;
short evt = 0;
if (trig & EPOLLIN)
evt |= evt_read;
if (trig & EPOLLPRI)
evt |= evt_urgent;
if (trig & EPOLLOUT)
evt |= evt_write;
if (trig & EPOLLHUP)
evt |= evt_close;
if (trig & EPOLLERR)
evt |= evt_error;
#ifdef EPOLLRDHUP
if (trig & EPOLLRDHUP)
evt |= evt_close;
#endif
return evt;
}
int net_initialize(int capacity)
{
int i;
max_connections = capacity;
num_connections = 0;
epfd = epoll_create(max_connections);
if (epfd == -1)
{
hub_log(log_error, "net_initialize(): epoll_create failed");
return -1;
}
events = hub_malloc_zero(sizeof(struct epoll_event) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
return -1;
}
monitor_allocate((size_t) capacity);
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
net_stats_initialize();
return 0;
}
int net_shutdown()
{
hub_log(log_trace, "Shutting down network monitor");
if (epfd != -1)
{
close(epfd);
}
hub_free(events);
hub_free(listeners);
return 0;
}
#ifdef DEBUG_EPOLL
uint64_t get_time_difference_in_msec(struct timeval before, struct timeval after)
{
uint64_t seconds = (after.tv_sec - before.tv_sec);
uint64_t out = seconds*1000;
if (seconds > 0)
out += ((after.tv_usec / 1000) + (1000 - (before.tv_usec / 1000)));
else
out += ((after.tv_usec - before.tv_usec) / 1000);
return out;
}
#endif
int net_wait(int timeout_ms)
{
int fired, n, max, ret;
struct net_event_listener* listener;
#ifdef DEBUG_EPOLL
struct timeval tm_before;
struct timeval tm_after;
gettimeofday(&tm_before, NULL);
dump_listeners();
#endif
fired = epoll_wait(epfd, events, num_connections, timeout_ms);
if (fired == -1) {
if (errno != EINTR)
{
hub_log(log_error, "net_wait(): epoll_wait failed");
}
return -1;
}
for (n = 0; n < fired; n++)
{
listener = (struct net_event_listener*) events[n].data.ptr;
listener->revents = get_poll_events(&events[n]);
hub_log(log_dump, "net_wait(): epoll event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
max = num_connections;
for (n = 0; n < max; n++)
{
listener = &listeners[n];
if (listener && listener->fd != -1 && listener->revents)
{
hub_log(log_dump, "net_wait(): epoll trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
ret = listener->handler(listener);
listener->revents = 0;
}
#ifdef DEBUG_EPOLL
else
{
if (listener)
hub_log(log_dump, "net_wait(): epoll trigger ignore (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
#endif
}
#ifdef DEBUG_EPOLL
gettimeofday(&tm_after, NULL);
size_t diff = (size_t) get_time_difference_in_msec(tm_before, tm_after);
dump_listeners();
hub_log(log_debug, "net_wait(): time=%dms, triggered=%d", diff, fired);
#endif
return 0;
}
int net_add(int fd, short events, void* data, net_event_handler_t handler)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_free_listener();
hub_log(log_trace, "net_add(): adding socket (fd=%d, pos=%d)", fd, pos);
if (!listener)
{
hub_log(log_error, "net_add(): unable to poll more sockets");
return -1;
}
net_event_listener_set(listener, fd, events, data, handler);
set_poll_events(&ev, events);
ev.data.ptr = listener;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
{
hub_log(log_error, "net_add(): epoll_ctl error while adding socket (fd=%d)", fd);
net_event_listener_clear(listener);
return -1;
}
num_connections++;
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
int net_modify(int fd, short events)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_modify(): modifying socket events (fd=%d)", fd);
if (!listener)
{
hub_log(log_error, "net_modify(): unable to find socket.");
return -1;
}
listener->events = events;
set_poll_events(&ev, events);
ev.data.ptr = listener;
if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
hub_log(log_error, "net_add(): epoll_ctl error while modifying socket (fd=%d)", fd);
return -1;
}
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
int net_remove(int fd)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_remove(): removing socket (fd=%d, pos=%d)", fd, pos);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
return -1;
}
net_event_listener_clear(listener);
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev) < 0)
{
hub_log(log_error, "net_remove(): epoll_ctl error while removing socket (fd=%d)", fd);
return -1;
}
num_connections--;
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
#endif /* HAVE_EPOLL */

290
src/network-kqueue.c Normal file
View File

@@ -0,0 +1,290 @@
/*
* 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/>.
*
*/
#include "uhub.h"
#ifdef HAVE_KQUEUE
static struct kevent* events = 0;
static struct kevent* change = 0;
static int kfd = -1;
static void set_poll_events(struct kevent* handle, short trigger)
{
if (!handle) {
hub_log(log_error, "OOOPS!!");
return;
}
memset(handle, 0, sizeof(struct kevent));
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
handle->filter |= EVFILT_READ;
if (trigger & evt_write /* || trigger & evt_accept*/)
handle->filter |= EVFILT_WRITE;
}
static short get_poll_events(struct kevent* handle)
{
short trig = handle->flags;
short evt = 0;
if (trig & EVFILT_READ)
evt |= evt_read;
if (trig & EVFILT_WRITE)
evt |= evt_write;
if (trig & EV_EOF)
{
evt |= evt_close;
if (handle->fflags)
evt |= evt_error;
}
if (handle->filter == -1)
{
evt |= evt_error;
}
if (handle->data)
{
evt |= evt_accept;
}
if (evt)
{
hub_log(log_error, "Evt: fd=%d, filter=%d, flags=%d, fflags=%d, data=%d evt=%#x", handle->ident, handle->filter, handle->flags, handle->fflags, (int) handle->data, evt);
}
return evt;
}
int net_initialize(int capacity)
{
int i;
max_connections = capacity;
num_connections = 0;
kfd = kqueue();
if (kfd == -1)
{
hub_log(log_error, "net_initialize(): kqueue failed");
return -1;
}
events = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
return -1;
}
change = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
hub_free(events);
return -1;
}
listeners = (void*) hub_malloc_zero(sizeof(struct net_event_listener) * max_connections);
if (!listeners)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
hub_free(change);
hub_free(events);
return -1;
}
for (i = 0; i < max_connections; i++)
{
listeners[i].fd = -1;
}
net_stats_initialize();
return 0;
}
int net_shutdown()
{
if (kfd != -1) {
return close(kfd);
}
hub_free(events);
hub_free(change);
hub_free(listeners);
return 0;
}
int net_wait(int timeout_ms)
{
int fired, n, max, ret;
struct net_event_listener* listener;
struct timespec timeout = { (timeout_ms / 1000), (timeout_ms % 1000) * 1000 };
fired = kevent(kfd, events, num_connections, change, num_connections, &timeout);
if (fired == -1) {
if (errno != EINTR)
{
hub_log(log_error, "net_wait(): kevent failed");
}
return -1;
}
for (n = 0; n < fired; n++)
{
listener = (struct net_event_listener*) events[n].udata;
if (listener)
{
listener->revents = get_poll_events(&events[n]);
hub_log(log_dump, "net_wait(): kqueue event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
}
max = num_connections;
for (n = 0; n < max; n++)
{
listener = &listeners[n];
if (listener && listener->fd != -1 && listener->revents != 0)
{
hub_log(log_dump, "net_wait(): kqueue trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
ret = listener->handler(listener);
listener->revents = 0;
}
}
return 0;
}
int net_add(int fd, short events_, void* data, net_event_handler_t handler)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_add(): adding socket (fd=%d)", fd);
if (listener)
{
/* Already added! */
return -1;
}
listener = monitor_get_free_listener();
if (!listener)
{
hub_log(log_error, "net_add(): unable to poll more sockets");
return -1;
}
net_event_listener_set(listener, fd, events_, data, handler);
event = &events[pos];
set_poll_events(event, events_);
event->ident = fd;
event->flags |= EV_ADD;
event->flags |= EV_ONESHOT;
#ifdef __APPLE__
event->flags |= EV_ENABLE;
#endif
event->udata = listener;
num_connections++;
return 0;
}
int net_modify(int fd, short events_)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_modify(): modifying socket (fd=%d)", fd);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_modify(): unable to find socket (fd=%d)", fd);
return -1;
}
event = &events[pos];
// set_poll_events(event, events_);
event->ident = fd;
event->flags |= EV_ADD;
event->flags |= EV_ONESHOT;
#ifdef __APPLE__
event->flags |= EV_ENABLE;
#endif
return 0;
}
int net_remove(int fd)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_remove(): removing socket (fd=%d)", fd);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
return -1;
}
net_event_listener_clear(listener);
event = &events[pos];
event->ident = fd;
event->filter = 0;
event->flags = EV_DELETE;
#ifdef __APPLE__
event->flasg |= EV_DISABLE;
#endif
event->fflags = 0;
event->data = 0;
event->udata = 0;
num_connections--;
return 0;
}
#endif /* HAVE_KQUEUE */

View File

@@ -40,19 +40,16 @@ int net_initialize()
struct WSAData wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
{
LOG_ERROR("Unable to initialize winsock.");
hub_log(log_error, "Unable to initialize winsock.");
return -1;
}
#endif /* WINSOCK */
LOG_TRACE("Initializing network monitor.");
hub_log(log_trace, "Initializing network monitor.");
net_stats_initialize();
#ifdef SSL_SUPPORT
LOG_TRACE("Initializing OpenSSL...");
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
/* FIXME: Initialize OpenSSL here. */
#endif /* SSL_SUPPORT */
net_initialized = 1;
@@ -61,27 +58,12 @@ int net_initialize()
return -1;
}
size_t net_get_max_sockets()
{
#ifdef HAVE_GETRLIMIT
struct rlimit limits;
if (getrlimit(RLIMIT_NOFILE, &limits) == 0)
{
return limits.rlim_max;
}
LOG_ERROR("getrlimit() failed");
#else
LOG_ERROR("System does not have getrlimit(): constrained to 1024 sockets");
#endif /* HAVE_GETRLIMIT */
return 1024;
}
int net_destroy()
int net_shutdown()
{
if (net_initialized)
{
LOG_TRACE("Shutting down network monitor");
hub_log(log_trace, "Shutting down network monitor");
#ifdef SSL_SUPPORT
/* FIXME: Shutdown OpenSSL here. */
@@ -96,11 +78,6 @@ int net_destroy()
return -1;
}
static void net_error_out(int fd, const char* func)
{
int err = net_error();
LOG_ERROR("%s, fd=%d: %s (%d)", func, fd, net_error_string(err), err);
}
int net_error()
{
@@ -126,42 +103,22 @@ const char* net_error_string(int code)
static int net_setsockopt(int fd, int level, int opt, const void* optval, socklen_t optlen)
{
int ret = -1;
#ifdef WINSOCK
ret = setsockopt(fd, level, opt, (const char*) optval, optlen);
return setsockopt(fd, level, opt, (const char*) optval, optlen);
#else
ret = setsockopt(fd, level, opt, optval, optlen);
return setsockopt(fd, level, opt, optval, optlen);
#endif
if (ret == -1)
{
net_error_out(fd, "net_setsockopt");
}
return ret;
}
static int net_getsockopt(int fd, int level, int opt, void* optval, socklen_t* optlen)
{
int ret = -1;
#ifdef WINSOCK
ret = getsockopt(fd, level, opt, (char*) optval, optlen);
#else
ret = getsockopt(fd, level, opt, optval, optlen);
#endif
if (ret == -1)
{
net_error_out(fd, "net_getsockopt");
}
return ret;
}
int net_set_nonblocking(int fd, int toggle)
{
int ret = -1;
int ret;
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_nonblocking(): fd=%d", fd);
#endif
#ifdef WINSOCK
u_long on = toggle ? 1 : 0;
ret = ioctlsocket(fd, FIONBIO, &on);
@@ -170,27 +127,36 @@ int net_set_nonblocking(int fd, int toggle)
#endif
if (ret == -1)
{
net_error_out(fd, "net_set_nonblocking");
hub_log(log_error, "net_set_nonblocking(): ioctl failed (fd=%d): %s", fd, net_error_string(net_error()));
return -1;
}
return ret;
return 0;
}
/* NOTE: Possibly only supported on BSD and OSX? */
int net_set_nosigpipe(int fd, int toggle)
{
int ret = -1;
#ifdef SO_NOSIGPIPE
int ret;
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_nosigpipe(): fd=%d", fd);
#endif
ret = net_setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &toggle, sizeof(toggle));
if (ret == -1)
{
net_error_out(fd, "net_set_nosigpipe");
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
return -1;
}
#endif
return ret;
return 0;
}
int net_set_close_on_exec(int fd, int toggle)
{
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_close_on_exec(): fd=%d", fd);
#endif
#ifdef WINSOCK
return -1; /* FIXME: How is this done on Windows? */
#else
@@ -198,63 +164,54 @@ int net_set_close_on_exec(int fd, int toggle)
#endif
}
int net_set_linger(int fd, int toggle)
{
int ret;
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_linger(): fd=%d", fd);
#endif
ret = net_setsockopt(fd, SOL_SOCKET, SO_LINGER, &toggle, sizeof(toggle));
if (ret == -1)
{
net_error_out(fd, "net_set_linger");
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
return -1;
}
return ret;
return 0;
}
int net_set_keepalive(int fd, int toggle)
{
int ret;
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_keepalive(): fd=%d", fd);
#endif
ret = net_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &toggle, sizeof(toggle));
if (ret == -1)
{
net_error_out(fd, "net_set_keepalive");
hub_log(log_error, "net_set_keepalive(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
return -1;
}
return ret;
return 0;
}
int net_set_reuseaddress(int fd, int toggle)
{
int ret;
#ifdef NETAPI_DUMP
hub_log(log_dump, "net_set_reuseaddress(): fd=%d", fd);
#endif
ret = net_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &toggle, sizeof(toggle));
if (ret == -1)
{
net_error_out(fd, "net_set_reuseaddress");
hub_log(log_error, "net_set_reuseaddress(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
return -1;
}
return ret;
return 0;
}
int net_set_sendbuf_size(int fd, size_t size)
{
return net_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}
int net_get_sendbuf_size(int fd, size_t* size)
{
socklen_t sz = sizeof(*size);
return net_getsockopt(fd, SOL_SOCKET, SO_SNDBUF, size, &sz);
}
int net_set_recvbuf_size(int fd, size_t size)
{
return net_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}
int net_get_recvbuf_size(int fd, size_t* size)
{
socklen_t sz = sizeof(*size);
return net_getsockopt(fd, SOL_SOCKET, SO_RCVBUF, size, &sz);
}
int net_close(int fd)
{
@@ -278,32 +235,6 @@ int net_close(int fd)
return ret;
}
int net_shutdown_r(int fd)
{
#ifdef WINSOCK
return shutdown(fd, SD_RECEIVE);
#else
return shutdown(fd, SHUT_RD);
#endif
}
int net_shutdown_w(int fd)
{
#ifdef WINSOCK
return shutdown(fd, SD_SEND);
#else
return shutdown(fd, SHUT_WR);
#endif
}
int net_shutdown_rw(int fd)
{
#ifdef WINSOCK
return shutdown(fd, SD_BOTH);
#else
return shutdown(fd, SHUT_RDWR);
#endif
}
int net_accept(int fd, struct ip_addr_encap* ipaddr)
{
@@ -337,7 +268,7 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr)
case EWOULDBLOCK:
break;
default:
net_error_out(fd, "net_accept");
hub_log(log_error, "net_accept(): accept failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
return -1;
}
@@ -352,18 +283,7 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr)
ipaddr->af = addr4->sin_family;
if (ipaddr->af == AF_INET6)
{
char address[INET6_ADDRSTRLEN+1] = { 0, };
net_address_to_string(AF_INET6, (void*) &addr6->sin6_addr, address, INET6_ADDRSTRLEN+1);
if (!strncmp(address, "::ffff:", 7))
{
/* 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;
}
else
{
memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
}
memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
}
else
{
@@ -383,7 +303,7 @@ int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
{
if (net_error() != EINPROGRESS)
{
net_error_out(fd, "net_connect");
hub_log(log_error, "net_connect(): connect failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
}
}
@@ -405,12 +325,13 @@ int net_is_ipv6_supported()
if (net_error() == EAFNOSUPPORT)
#endif
{
LOG_TRACE("net_is_ipv6_supported(): IPv6 is not supported on this system.");
hub_log(log_trace, "net_is_ipv6_supported(): IPv6 is not supported on this system.");
is_ipv6_supported = 0;
return 0;
}
net_error_out(ret, "net_is_ipv6_supported");
hub_log(log_error, "net_is_ipv6_supported(): Unknown error (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
}
else
{
@@ -418,7 +339,7 @@ int net_is_ipv6_supported()
int off = 0;
if (net_setsockopt(ret, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
{
LOG_ERROR("net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
hub_log(log_error, "net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
is_ipv6_supported = 0;
}
else
@@ -440,7 +361,7 @@ int net_socket_create(int af, int type, int protocol)
int sd = socket(af, type, protocol);
if (sd == -1)
{
net_error_out(sd, "net_socket_create");
hub_log(log_error, "net_socket_create(): socket failed (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
}
#ifdef SOCK_DUAL_STACK_OPT
@@ -450,7 +371,7 @@ int net_socket_create(int af, int type, int protocol)
int off = 0;
if (net_setsockopt(sd, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
{
LOG_ERROR("net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
hub_log(log_error, "net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
}
}
#endif
@@ -574,18 +495,19 @@ const char* net_get_peer_address(int fd)
{
return &address[7];
}
hub_log(log_trace, "net_get_peer_address(): address=%s", address);
return address;
}
else
{
net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
hub_log(log_trace, "net_get_peer_address(): address=%s", address);
return address;
}
}
else
{
net_error_out(fd, "net_get_peer_address");
net_stats_add_error();
hub_log(log_error, "net_get_peer_address(): getsockname failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
}
return "0.0.0.0";
@@ -603,7 +525,7 @@ ssize_t net_recv(int fd, void* buf, size_t len, int flags)
{
if (net_error() != EWOULDBLOCK)
{
/* net_error_out(fd, "net_recv"); */
hub_log(log_debug, "net_recv(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
}
}
@@ -611,7 +533,7 @@ ssize_t net_recv(int fd, void* buf, size_t len, int flags)
}
ssize_t net_send(int fd, const void* buf, size_t len, int flags)
ssize_t net_send(int fd, void* buf, size_t len, int flags)
{
ssize_t ret = send(fd, buf, len, flags);
if (ret >= 0)
@@ -622,7 +544,7 @@ ssize_t net_send(int fd, const void* buf, size_t len, int flags)
{
if (net_error() != EWOULDBLOCK)
{
/* net_error_out(fd, "net_send"); */
hub_log(log_debug, "net_send(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
}
}
@@ -635,7 +557,7 @@ int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
int ret = bind(fd, my_addr, addrlen);
if (ret == -1)
{
net_error_out(fd, "net_bind");
hub_log(log_error, "net_bind(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
}
return ret;
@@ -647,7 +569,7 @@ int net_listen(int fd, int backlog)
int ret = listen(fd, backlog);
if (ret == -1)
{
net_error_out(fd, "net_listen");
hub_log(log_error, "net_listen(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
net_stats_add_error();
}
return ret;
@@ -663,12 +585,14 @@ void net_stats_initialize()
stats.timestamp = time(NULL);
}
void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total)
{
*intermediate = &stats;
*total = &stats_total;
}
void net_stats_reset()
{
stats_total.tx += stats.tx;
@@ -681,31 +605,37 @@ void net_stats_reset()
stats.timestamp = time(NULL);
}
int net_stats_timeout()
{
return (difftime(time(NULL), stats.timestamp) > TIMEOUT_STATS) ? 1 : 0;
}
void net_stats_add_tx(size_t bytes)
{
stats.tx += bytes;
}
void net_stats_add_rx(size_t bytes)
{
stats.rx += bytes;
}
void net_stats_add_accept()
{
stats.accept++;
}
void net_stats_add_error()
{
stats.errors++;
}
void net_stats_add_close()
{
stats.closed++;

View File

@@ -30,17 +30,6 @@ struct net_statistics
size_t errors;
};
struct net_socket_t;
#define NET_WANT_READ 0x01
#define NET_WANT_WRITE 0x02
#define NET_WANT_ACCEPT 0x08
#define NET_WANT_SSL_READ 0x10
#define NET_WANT_SSL_WRITE 0x20
#define NET_WANT_SSL_ACCEPT 0x40
#define NET_WANT_SSL_CONNECT 0x40
#define NET_WANT_SSL_X509_LOOKUP 0x80
/**
* Initialize the socket monitor subsystem.
* On some operating systems this will also involve loading the TCP/IP stack
@@ -58,7 +47,7 @@ extern int net_initialize();
*
* @return -1 on error, 0 on success
*/
extern int net_destroy();
extern int net_shutdown();
/**
* @return the number of sockets currrently being monitored.
@@ -87,20 +76,11 @@ extern const char* net_error_string(int code);
*/
extern int net_socket_create(int af, int type, int protocol);
/**
* Returns the maximum number of file/socket descriptors.
*/
extern size_t net_get_max_sockets();
/**
* A wrapper for the close() function call.
*/
extern int net_close(int fd);
extern int net_shutdown_r(int fd);
extern int net_shutdown_w(int fd);
extern int net_shutdown_rw(int fd);
/**
* A wrapper for the accept() function call.
* @param fd socket descriptor
@@ -171,38 +151,6 @@ extern int net_set_linger(int fd, int toggle);
*/
extern int net_set_reuseaddress(int fd, int toggle);
/**
* Set the send buffer size for the socket.
* @param fd socket descriptor
* @param size size to set
* @return -1 on error, 0 on success.
*/
extern int net_set_sendbuf_size(int fd, size_t size);
/**
* Get the send buffer size for the socket.
* @param fd socket descriptor
* @param[out] size existing size, cannot be NULL.
* @return -1 on error, 0 on success.
*/
extern int net_get_sendbuf_size(int fd, size_t* size);
/**
* Set the receive buffer size for the socket.
* @param fd socket descriptor
* @param size size to set
* @return -1 on error, 0 on success.
*/
extern int net_set_recvbuf_size(int fd, size_t size);
/**
* Get the receive buffer size for the socket.
* @param fd socket descriptor
* @param[out] size existing size, cannot be NULL.
* @return -1 on error, 0 on success.
*/
extern int net_get_recvbuf_size(int fd, size_t* size);
/**
* A wrapper for the recv() function call.
*/
@@ -211,7 +159,7 @@ extern ssize_t net_recv(int fd, void* buf, size_t len, int flags);
/**
* A wrapper for the send() function call.
*/
extern ssize_t net_send(int fd, const void* buf, size_t len, int flags);
extern ssize_t net_send(int fd, void* buf, size_t len, int flags);
/**
* This tries to create a AF_INET6 socket.
@@ -262,6 +210,11 @@ extern void net_stats_get(struct net_statistics** intermediate, struct net_stati
#if defined(WINSOCK) && !defined(__CYGWIN__)
// #define EINTR WSAEINTR
// #define EACCES WSAEACCES
// #define EFAULT WSAEFAULT
// #define EINVAL WSAEINVAL
// #define EMFILE WSAEMFILE
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
#define EALREADY WSAEALREADY
@@ -290,8 +243,10 @@ extern void net_stats_get(struct net_statistics** intermediate, struct net_stati
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
#define ELOOP WSAELOOP
// #define ENAMETOOLONG WSAENAMETOOLONG
#define EHOSTDOWN WSAEHOSTDOWN
#define EHOSTUNREACH WSAEHOSTUNREACH
// #define ENOTEMPTY WSAENOTEMPTY
#define EPROCLIM WSAEPROCLIM
#define EUSERS WSAEUSERS
#define EDQUOT WSAEDQUOT

View File

@@ -1,52 +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/>.
*
*/
#include "uhub.h"
extern struct hub_info* g_hub;
void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events)
{
con->sd = sd;
con->ptr = (void*) ptr;
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr);
event_base_set(g_hub->evbase, &con->event);
event_add(&con->event, 0);
}
void net_con_update(struct net_connection* con, int events)
{
if (event_pending(&con->event, EV_READ | EV_WRITE, 0) == events)
return;
event_del(&con->event);
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr);
event_add(&con->event, 0);
}
void net_con_close(struct net_connection* con)
{
if (!event_pending(&con->event, EV_READ | EV_WRITE, 0))
return;
event_del(&con->event);
net_close(con->sd);
con->sd = -1;
}

View File

@@ -1,41 +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/>.
*
*/
#ifndef HAVE_UHUB_NETWORK_CONNECTION_H
#define HAVE_UHUB_NETWORK_CONNECTION_H
#include "uhub.h"
struct net_connection
{
int sd; /** socket descriptor */
void* ptr; /** data pointer */
struct event event; /** libevent struct for read/write events */
#ifdef SSL_SUPPORT
SSL* ssl; /** SSL handle */
#endif /* SSL_SUPPORT */
};
extern void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events);
extern void net_con_update(struct net_connection* con, int events);
extern void net_con_close(struct net_connection* con);
#endif /* HAVE_UHUB_NETWORK_CONNECTION_H */

52
src/plugin.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* 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/>.
*
*/
typedef void (*plugin_event_startup)(struct hub*);
typedef void (*plugin_event_shutdown)(struct hub*);
typedef void (*plugin_event_user_login)(struct hub*, struct user*);
typedef void (*plugin_event_user_logout)(struct hub*, struct user*);
typedef int (*plugin_event_connect)(struct hub*, struct ip_addr_encap);
typedef void (*plugin_event_disconnect)(struct hub*, struct user*);
typedef int (*plugin_event_message)(struct hub*, struct user*, struct adc_message*);
typedef void (*plugin_event_support)(struct hub*, struct user*, int);
struct uhub_plugin
{
/** Starting the hub */
plugin_event_startup evt_startup;
/** Shutting down the hub */
plugin_event_shutdown evt_shutdown;
/** Someone connected to the hub (we only have IP at this point). */
plugin_event_connect evt_connect;
/** Someone disconnected from the hub (but was not successfully logged in). */
plugin_event_disconnect evt_disconnect;
/** A client sent a message about which protocol extensions it supports */
plugin_event_support evt_support;
/** A client was successfully logged in to the hub */
plugin_event_user_login evt_login;
/** A client (previously logged in) has disconnected. */
plugin_event_user_logout evt_logout;
};

266
src/route.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* 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/>.
*
*/
#include "uhub.h"
int route_message(struct user* u, struct adc_message* msg)
{
struct user* target = NULL;
switch (msg->cache[0])
{
case 'B': /* Broadcast to all logged in clients */
route_to_all(u->hub, msg);
break;
case 'D':
target = uman_get_user_by_sid(u->hub, msg->target);
if (target)
{
route_to_user(target, msg);
}
break;
case 'E':
target = uman_get_user_by_sid(u->hub, msg->target);
if (target)
{
route_to_user(target, msg);
route_to_user(u, msg);
}
break;
case 'F':
route_to_subscribers(u->hub, msg);
break;
default:
/* Ignore the message */
break;
}
return 0;
}
static void queue_command(struct user* user, struct adc_message* msg__, int offset)
{
struct adc_message* msg = adc_msg_incref(msg__);
list_append(user->send_queue, msg);
#ifdef DEBUG_SENDQ
hub_log(log_trace, "SENDQ: user=%p, msg=%p (%zu), offset=%d, length=%d, total_length=%d", user, msg, msg->references, offset, msg->length, user->send_queue_size);
#endif
user->send_queue_size += msg->length - offset;
if (list_size(user->send_queue) == 1)
{
user->send_queue_offset = offset;
user->tm_last_write = time(NULL);
}
}
// #define ALWAYS_QUEUE_MESSAGES
static size_t get_max_send_queue(struct hub_info* hub)
{
/* TODO: More dynamic send queue limit, for instance:
* return MAX(hub->config->max_send_buffer, (hub->config->max_recv_buffer * hub_get_user_count(hub)));
*/
return hub->config->max_send_buffer;
}
static size_t get_max_send_queue_soft(struct hub_info* hub)
{
return hub->config->max_send_buffer_soft;
}
/*
* @return 1 if send queue is OK.
* -1 if send queue is overflowed
* 0 if soft send queue is overflowed (not implemented at the moment)
*/
static int check_send_queue(struct user* user, struct adc_message* msg)
{
if (user_flag_get(user, flag_user_list))
return 1;
if ((user->send_queue_size + msg->length) > get_max_send_queue(user->hub))
return -1;
if (user->send_queue_size > get_max_send_queue_soft(user->hub) && msg->priority < 0)
return 0;
return 1;
}
int route_to_user(struct user* user, struct adc_message* msg)
{
int ret;
#if LOG_SEND_MESSAGES_WHEN_ROUTED
char* data = strndup(msg->cache, msg->length-1);
hub_log(log_protocol, "send %s: %s", sid_to_string(user->sid), data);
free(data);
#endif
#ifndef ALWAYS_QUEUE_MESSAGES
if (user->send_queue_size == 0 && !user_is_disconnecting(user))
{
ret = net_send(user->sd, msg->cache, msg->length, UHUB_SEND_SIGNAL);
if (ret == msg->length)
{
return 1;
}
if (ret >= 0 || (ret == -1 && net_error() == EWOULDBLOCK))
{
queue_command(user, msg, ret);
if (user->send_queue_size && user->ev_write)
event_add(user->ev_write, NULL);
}
else
{
/* A socket error occured */
user_disconnect(user, quit_socket_error);
return 0;
}
}
else
#endif
{
ret = check_send_queue(user, msg);
if (ret == -1)
{
/* User is not able to swallow the data, let's cut our losses and disconnect. */
user_disconnect(user, quit_send_queue);
}
else if (ret == 1)
{
/* queue command */
queue_command(user, msg, 0);
if (user->ev_write)
event_add(user->ev_write, NULL);
}
else
{
/* do not queue command as our soft-limits are exceeded */
}
}
return 1;
}
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
struct user* user = (struct user*) list_get_first(hub->users->list);
while (user)
{
route_to_user(user, command);
user = (struct user*) list_get_next(hub->users->list);
}
return 0;
}
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
int do_send;
char* tmp;
struct user* user = (struct user*) list_get_first(hub->users->list);
while (user)
{
if (user->feature_cast)
{
do_send = 1;
tmp = list_get_first(command->feature_cast_include);
while (tmp)
{
if (!user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_include);;
}
if (!do_send) {
user = (struct user*) list_get_next(hub->users->list);
continue;
}
tmp = list_get_first(command->feature_cast_exclude);
while (tmp)
{
if (user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_exclude);
}
if (do_send)
{
route_to_user(user, command);
}
}
user = (struct user*) list_get_next(hub->users->list);
}
return 0;
}
int route_info_message(struct user* u)
{
if (!user_is_nat_override(u))
{
return route_to_all(u->hub, u->info);
}
else
{
struct adc_message* cmd = adc_msg_copy(u->info);
const char* address = ip_convert_to_string(&u->ipaddr);
struct user* user = 0;
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
user = (struct user*) list_get_first(u->hub->users->list);
while (user)
{
if (user_is_nat_override(user))
route_to_user(user, cmd);
else
route_to_user(user, u->info);
user = (struct user*) list_get_next(u->hub->users->list);
}
adc_msg_free(cmd);
}
return 0;
}

View File

@@ -23,17 +23,12 @@
/**
* Route a message by sending it to it's final destination.
*/
extern int route_message(struct hub_info* hub, struct hub_user* u, struct adc_message* msg);
/**
* Send queued messages.
*/
extern int route_flush_pipeline(struct hub_info* hub, struct hub_user* u);
extern int route_message(struct user* u, struct adc_message* msg);
/**
* Transmit message directly to one user.
*/
extern int route_to_user(struct hub_info* hub, struct hub_user*, struct adc_message* command);
extern int route_to_user(struct user*, struct adc_message* command);
/**
* Broadcast message to all users.
@@ -50,7 +45,7 @@ extern int route_to_subscribers(struct hub_info* hub, struct adc_message* comman
* This will ensure the correct IP is seen by other users
* in case nat override is in use.
*/
extern int route_info_message(struct hub_info* hub, struct hub_user* user);
extern int route_info_message(struct user* user);
#endif /* HAVE_UHUB_ROUTE_H */

61
src/sid.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* 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/>.
*
*/
#include "uhub.h"
const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
char* sid_to_string(sid_t sid_)
{
static char t_sid[5];
sid_t sid = (sid_ & 0xFFFFF); /* 20 bits only */
sid_t A, B, C, D = 0;
D = (sid % 32);
sid = (sid - D) / 32;
C = (sid % 32);
sid = (sid - C) / 32;
B = (sid % 32);
sid = (sid - B) / 32;
A = (sid % 32);
t_sid[0] = BASE32_ALPHABET[A];
t_sid[1] = BASE32_ALPHABET[B];
t_sid[2] = BASE32_ALPHABET[C];
t_sid[3] = BASE32_ALPHABET[D];
t_sid[4] = 0;
return t_sid;
}
sid_t string_to_sid(const char* sid)
{
sid_t nsid = 0;
sid_t n, x;
sid_t factors[] = { 32768, 1024, 32, 1};
if (!sid || strlen(sid) != 4) return 0;
for (n = 0; n < 4; n++) {
for (x = 0; x < strlen(BASE32_ALPHABET); x++)
if (sid[n] == BASE32_ALPHABET[x]) break;
if (x == 32) return 0;
nsid += x * factors[n];
}
return nsid;
}

View File

@@ -22,19 +22,44 @@
#define SID_MAX 1048576
struct sid_pool;
struct hub_user;
extern const char* BASE32_ALPHABET;
extern char* sid_to_string(sid_t sid_);
extern sid_t string_to_sid(const char* sid);
extern struct sid_pool* sid_pool_create(sid_t max);
extern void sid_pool_destroy(struct sid_pool*);
struct sid_map
{
struct user* ptr;
struct sid_map* next;
};
extern sid_t sid_alloc(struct sid_pool*, struct hub_user*);
/**
* Session IDs are heavily reused, since they are a fairly scarce
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
* value and 'AAAA' (0) is reserved for the hub.
*
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
*
* When allocating a session ID:
* - If 'count' is less than the pool size (max-min), then allocate within the pool
* - Increase the pool size (see below)
* - If unable to do that, hub is really full - don't let anyone in!
*
* When freeing a session ID:
* - If the session ID being freed is 'max', then decrease the pool size by one.
*
*/
struct sid_pool
{
sid_t min;
sid_t max;
sid_t count;
struct sid_map* map;
};
extern void sid_initialize(struct sid_pool*);
extern sid_t sid_alloc(struct sid_pool*, struct user*);
extern void sid_free(struct sid_pool*, sid_t);
extern struct hub_user* sid_lookup(struct sid_pool*, sid_t);

View File

@@ -23,26 +23,6 @@
/* Debugging */
/* #define NETWORK_DUMP_DEBUG */
/* #define MEMORY_DEBUG */
/* #define DEBUG_SENDQ 1 */
#if USE_REGPARM && __GNUC__ >= 3
#define REGPRM1 __attribute__((regparm(1)))
#define REGPRM2 __attribute__((regparm(2)))
#define REGPRM3 __attribute__((regparm(3)))
#else
#define REGPRM1
#define REGPRM2
#define REGPRM3
#endif
#ifndef FORCEINLINE
#if __GNUC__ < 3
#define FORCEINLINE inline
#else
#define FORCEINLINE inline __attribute__((always_inline))
#endif
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
@@ -83,10 +63,8 @@
#ifndef WIN32
#include <grp.h>
#include <pwd.h>
#include <sys/resource.h>
#define HAVE_STRNDUP
#define HAVE_MEMMEM
#define HAVE_GETRLIMIT
#endif
#ifdef SSL_SUPPORT
@@ -144,46 +122,41 @@
#define TIGERSIZE 24
#define MAX_RECV_BUF 65535
#define MAX_SEND_BUF 65535
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#include "adc/adcconst.h"
#include "adcconst.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) (a < b ? a : b)
#define MAX(a, b) (a > b ? a : b)
#ifdef __cplusplus
extern "C" {
#endif
#include "util/ipcalc.h"
#include "util/list.h"
#include "util/log.h"
#include "util/memory.h"
#include "util/misc.h"
#include "util/tiger.h"
#include "adc/sid.h"
#include "adc/message.h"
#include "network/network.h"
#include "network/connection.h"
#include "core/auth.h"
#include "core/config.h"
#include "core/eventid.h"
#include "core/eventqueue.h"
#include "core/netevent.h"
#include "core/hubio.h"
#include "core/user.h"
#include "core/usermanager.h"
#include "core/route.h"
#include "core/hub.h"
#include "core/commands.h"
#include "core/inf.h"
#include "core/hubevent.h"
#include "memory.h"
#include "misc.h"
#include "eventid.h"
#include "eventqueue.h"
#include "ipcalc.h"
#include "list.h"
#include "sid.h"
#include "network.h"
#include "netevent.h"
#include "auth.h"
#include "tiger.h"
#include "config.h"
#include "log.h"
#include "user.h"
#include "usermanager.h"
#include "message.h"
#include "route.h"
#include "hub.h"
#include "commands.h"
#include "inf.h"
#include "hubevent.h"
#ifdef __cplusplus
}

347
src/user.c Normal file
View File

@@ -0,0 +1,347 @@
/*
* 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/>.
*
*/
#include "uhub.h"
struct user* user_create(struct hub_info* hub, int sd)
{
struct user* user = NULL;
hub_log(log_trace, "user_create(), hub=%p, sd=%d", hub, sd);
user = (struct user*) hub_malloc_zero(sizeof(struct user));
if (user == NULL)
return NULL; /* OOM */
user->ev_write = hub_malloc_zero(sizeof(struct event));
user->ev_read = hub_malloc_zero(sizeof(struct event));
if (!user->ev_write || !user->ev_read)
{
hub_free(user->ev_read);
hub_free(user->ev_write);
hub_free(user);
return NULL;
}
user->sd = sd;
user->tm_connected = time(NULL);
user->hub = hub;
user->feature_cast = 0;
user->send_queue = list_create();
user->send_queue_offset = 0;
user->send_queue_size = 0;
user->recv_buf_offset = 0;
user->recv_buf = 0;
user_set_state(user, state_protocol);
return user;
}
static void clear_send_queue_callback(void* ptr)
{
adc_msg_free((struct adc_message*) ptr);
}
void user_destroy(struct user* user)
{
hub_log(log_trace, "user_destroy(), user=%p", user);
if (user->ev_write)
{
event_del(user->ev_write);
hub_free(user->ev_write);
user->ev_write = 0;
}
if (user->ev_read)
{
event_del(user->ev_read);
hub_free(user->ev_read);
user->ev_read = 0;
}
net_close(user->sd);
adc_msg_free(user->info);
user_clear_feature_cast_support(user);
if (user->recv_buf)
{
hub_free(user->recv_buf);
}
if (user->send_queue)
{
list_clear(user->send_queue, &clear_send_queue_callback);
list_destroy(user->send_queue);
}
hub_free(user);
}
void user_set_state(struct user* user, enum user_state state)
{
if ((user->state == state_cleanup && state != state_disconnected) || (user->state == state_disconnected))
{
puts("PANIC - Ignoring new state");
return;
}
user->state = state;
}
void user_set_info(struct user* user, struct adc_message* cmd)
{
adc_msg_free(user->info);
user->info = adc_msg_incref(cmd);
}
void user_update_info(struct user* u, struct adc_message* cmd)
{
char prefix[2];
char* argument;
size_t n = 0;
struct adc_message* cmd_new = adc_msg_copy(u->info);
if (!cmd_new)
{
/* FIXME: OOM! */
return;
}
/*
* FIXME: Optimization potential:
*
* remove parts of cmd that do not really change anything in cmd_new.
* this can save bandwidth if clients send multiple updates for information
* that does not really change anything.
*/
argument = adc_msg_get_argument(cmd, n++);
while (argument)
{
if (strlen(argument) >= 2)
{
prefix[0] = argument[0];
prefix[1] = argument[1];
adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
}
hub_free(argument);
argument = adc_msg_get_argument(cmd, n++);
}
user_set_info(u, cmd_new);
adc_msg_free(cmd_new);
}
static int convert_support_fourcc(int fourcc)
{
switch (fourcc)
{
case FOURCC('B','A','S','0'): /* Obsolete */
#ifndef OLD_ADC_SUPPORT
return 0;
#endif
case FOURCC('B','A','S','E'):
return feature_base;
case FOURCC('A','U','T','0'):
return feature_auto;
case FOURCC('U','C','M','0'):
case FOURCC('U','C','M','D'):
return feature_ucmd;
case FOURCC('Z','L','I','F'):
return feature_zlif;
case FOURCC('B','B','S','0'):
return feature_bbs;
case FOURCC('T','I','G','R'):
return feature_tiger;
case FOURCC('B','L','O','M'):
case FOURCC('B','L','O','0'):
return feature_bloom;
case FOURCC('P','I','N','G'):
return feature_ping;
case FOURCC('L','I','N','K'):
return feature_link;
default:
hub_log(log_debug, "Unknown extension: %x", fourcc);
return 0;
}
}
void user_support_add(struct user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags |= feature_mask;
}
int user_flag_get(struct user* user, enum user_flags flag)
{
return user->flags & flag;
}
void user_flag_set(struct user* user, enum user_flags flag)
{
user->flags |= flag;
}
void user_flag_unset(struct user* user, enum user_flags flag)
{
user->flags &= ~flag;
}
void user_set_nat_override(struct user* user)
{
user_flag_set(user, flag_nat);
}
int user_is_nat_override(struct user* user)
{
return user_flag_get(user, flag_nat);
}
void user_support_remove(struct user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags &= ~feature_mask;
}
void user_schedule_destroy(struct user* user)
{
struct event_data post;
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_DESTROY;
post.ptr = user;
event_queue_post(user->hub->queue, &post);
}
void user_disconnect(struct user* user, int reason)
{
struct event_data post;
int need_notify = 0;
if (user_is_disconnecting(user))
{
return;
}
/* dont read more data from this user */
if (user->ev_read)
{
event_del(user->ev_read);
hub_free(user->ev_read);
user->ev_read = 0;
}
hub_log(log_trace, "user_disconnect(), user=%p, reason=%d, state=%d", user, reason, user->state);
need_notify = user_is_logged_in(user);
user->quit_reason = reason;
user_set_state(user, state_cleanup);
if (need_notify)
{
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_QUIT;
post.ptr = user;
event_queue_post(user->hub->queue, &post);
}
else
{
user->quit_reason = quit_unknown;
user_schedule_destroy(user);
}
}
int user_have_feature_cast_support(struct user* user, char feature[4])
{
char* tmp = list_get_first(user->feature_cast);
while (tmp)
{
if (strncmp(tmp, feature, 4) == 0)
return 1;
tmp = list_get_next(user->feature_cast);
}
return 0;
}
int user_set_feature_cast_support(struct user* u, char feature[4])
{
if (!u->feature_cast)
{
u->feature_cast = list_create();
}
if (!u->feature_cast)
{
return 0; /* OOM! */
}
list_append(u->feature_cast, hub_strndup(feature, 4));
return 1;
}
void user_clear_feature_cast_support(struct user* u)
{
if (u->feature_cast)
{
list_clear(u->feature_cast, &hub_free);
list_destroy(u->feature_cast);
u->feature_cast = 0;
}
}
int user_is_logged_in(struct user* user)
{
if (user->state == state_normal)
return 1;
return 0;
}
int user_is_connecting(struct user* user)
{
if (user->state == state_protocol || user->state == state_identify || user->state == state_verify)
return 1;
return 0;
}
int user_is_disconnecting(struct user* user)
{
if (user->state == state_cleanup || user->state == state_disconnected)
return 1;
return 0;
}

View File

@@ -20,8 +20,9 @@
#ifndef HAVE_UHUB_USER_H
#define HAVE_UHUB_USER_H
struct hub_info;
struct hub_iobuf;
enum user_state
{
@@ -33,6 +34,7 @@ enum user_state
state_disconnected = 5, /**<< "User is disconnected" */
};
enum user_flags
{
feature_base = 0x00000001, /** BASE: Basic configuration (required by all clients) */
@@ -50,10 +52,10 @@ enum user_flags
flag_want_read = 0x08000000, /** Need to read (SSL) */
flag_want_write = 0x10000000, /** Need to write (SSL) */
flag_user_list = 0x20000000, /** Send queue bypass (when receiving the send queue) */
flag_pipeline = 0x40000000, /** Hub message pipelining */
flag_nat = 0x80000000, /** nat override enabled */
flag_nat = 0x40000000, /** nat override enabled */
};
enum user_quit_reason
{
quit_unknown = 0,
@@ -70,10 +72,8 @@ enum user_quit_reason
quit_ghost_timeout = 11, /** The user is a ghost, and trying to login from another connection */
};
/** Returns an apropriate string for the given quit reason */
extern const char* user_get_quit_reason_string(enum user_quit_reason);
struct hub_user_info
struct user_info
{
sid_t sid; /** session ID */
char cid[MAX_CID_LEN+1]; /** global client ID */
@@ -85,7 +85,7 @@ struct hub_user_info
* as the number of bytes and files shared, and the number of hubs the
* user is connected to, etc.
*/
struct hub_user_limits
struct user_counts
{
uint64_t shared_size; /** Shared size in bytes */
size_t shared_files; /** The number of shared files */
@@ -96,32 +96,34 @@ struct hub_user_limits
size_t hub_count_total; /** The number of hubs connected to in total */
};
struct hub_user_net_io
struct user
{
struct net_connection connection; /** Connection data */
struct event timeout; /** timeout handling */
struct hub_recvq* recv_queue;
struct hub_sendq* send_queue;
int sd; /** socket descriptor */
struct event* ev_read; /** libevent struct for read events */
struct event* ev_write; /** libevent struct for write events */
enum user_state state; /** see enum user_state */
enum user_credentials credentials; /** see enum user_credentials */
struct user_info id; /** Contains nick name and CID */
int flags; /** see enum user_features */
char user_agent[MAX_UA_LEN+1];/** User agent string */
time_t tm_connected; /** time when user connected */
time_t tm_last_read; /** time the user last received something from the hub */
time_t tm_last_write; /** time the user last sent something to the hub */
struct ip_addr_encap ipaddr; /** IP address of connected user */
};
struct hub_user
{
struct hub_user_net_io net; /** Network information data */
enum user_state state; /** see enum user_state */
enum user_credentials credentials; /** see enum user_credentials */
struct hub_user_info id; /** Contains nick name and CID */
int flags; /** see enum user_features */
char user_agent[MAX_UA_LEN+1];/** User agent string */
struct linked_list* feature_cast; /** Features supported by feature cast */
struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */
size_t send_queue_offset; /** Send queue byte offset */
struct linked_list* send_queue; /** Send queue */
int send_queue_size; /** Size of send queue (in bytes, not messages) */
int send_queue_esize; /** Effective send queue size */
char* recv_buf; /** Recv buffer */
size_t recv_buf_offset; /** Recv buffer offset */
struct hub_info* hub; /** The hub instance this user belong to */
struct hub_user_limits limits; /** Data used for limitation */
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */
int quit_reason; /** Quit reason (see user_quit_reason) */
struct ip_addr_encap ipaddr; /** IP address of connected user */
struct user_counts limits; /** Data used for limitation */
#ifdef SSL_SUPPORT
SSL* ssl; /** SSL handle */
#endif /* SSL_SUPPORT */
};
@@ -135,14 +137,35 @@ struct hub_user
* @param sd socket descriptor associated with the user
* @return User object or NULL if not enough memory is available.
*/
extern struct hub_user* user_create(struct hub_info* hub, int sd);
extern struct user* user_create(struct hub_info* hub, int sd);
/**
* Delete a user.
*
* !WRONG! If the user is logged in a quit message is issued.
*/
extern void user_destroy(struct hub_user* user);
extern void user_destroy(struct user* user);
/**
* Will post a message that will delete the user later.
*/
extern void user_schedule_destroy(struct user* user);
/**
* Disconnect a user.
* This will mark the user connection ready for being terminated.
* A reason can be given using the enum user_quit_reason.
*
* Things to be done when calling this:
* - Mark the user with state_cleanup
*
* If the user is logged in to the hub:
* - post message: UHUB_EVENT_USER_QUIT
*
* @param user User to disconnect
* @param reason See enum user_quit_reason
*/
extern void user_disconnect(struct user* user, int reason);
/**
* This associates a INF message to the user.
@@ -151,53 +174,36 @@ extern void user_destroy(struct hub_user* user);
*
* @param info new inf message (can be NULL)
*/
extern void user_set_info(struct hub_user* user, struct adc_message* info);
extern void user_set_info(struct user* user, struct adc_message* info);
/**
* Update a user's INF message.
* Will parse replace all ellements in the user's inf message with
* the parameters from the cmd (merge operation).
*/
extern void user_update_info(struct hub_user* user, struct adc_message* cmd);
extern void user_update_info(struct user* user, struct adc_message* cmd);
/**
* Specify a user's state.
* NOTE: DON'T, unless you know what you are doing.
*/
extern void user_set_state(struct hub_user* user, enum user_state);
extern void user_set_state(struct user* user, enum user_state);
/**
* Returns 1 if the user is in state state_normal, or 0 otherwise.
*/
extern int user_is_logged_in(struct hub_user* user);
/**
* Returns 1 if the user is in state_protocol.
* Returns 0 otherwise.
*/
extern int user_is_protocol_negotiating(struct hub_user* user);
extern int user_is_logged_in(struct user* user);
/**
* Returns 1 if the user is in state_protocol, state_identify or state_verify.
* Returns 0 otherwise.
*/
extern int user_is_connecting(struct hub_user* user);
extern int user_is_connecting(struct user* user);
/**
* Returns 1 only if the user is in state_cleanup or state_disconnected.
*/
extern int user_is_disconnecting(struct hub_user* user);
/**
* Returns 1 if a user is protected, which includes users
* having any form of elevated privileges.
*/
extern int user_is_protected(struct hub_user* user);
/**
* Returns 1 if a user is registered, with or without privileges.
*/
extern int user_is_registered(struct hub_user* user);
extern int user_is_disconnecting(struct user* user);
/**
* User supports the protocol extension as given in fourcc.
@@ -207,7 +213,7 @@ extern int user_is_registered(struct hub_user* user);
*
* @see enum user_flags
*/
extern void user_support_add(struct hub_user* user, int fourcc);
extern void user_support_add(struct user* user, int fourcc);
/**
* User no longer supports the protocol extension as given in fourcc.
@@ -215,26 +221,26 @@ extern void user_support_add(struct hub_user* user, int fourcc);
* the hub.
* @see enum user_flags
*/
extern void user_support_remove(struct hub_user* user, int fourcc);
extern void user_support_remove(struct user* user, int fourcc);
/**
* Sets the nat override flag for a user, this allows users on the same
* subnet as a natted hub to spoof their IP in order to use active mode
* on a natted hub.
*/
extern void user_set_nat_override(struct hub_user* user);
extern int user_is_nat_override(struct hub_user* user);
extern void user_set_nat_override(struct user* user);
extern int user_is_nat_override(struct user* user);
/**
* Set a flag. @see enum user_flags
*/
extern void user_flag_set(struct hub_user* user, enum user_flags flag);
extern void user_flag_unset(struct hub_user* user, enum user_flags flag);
extern void user_flag_set(struct user* user, enum user_flags flag);
extern void user_flag_unset(struct user* user, enum user_flags flag);
/**
* Get a flag. @see enum user_flags
*/
extern int user_flag_get(struct hub_user* user, enum user_flags flag);
extern int user_flag_get(struct user* user, enum user_flags flag);
/**
* Check if a user supports 'feature' for feature casting (basis for 'Fxxx' messages)
@@ -244,7 +250,7 @@ extern int user_flag_get(struct hub_user* user, enum user_flags flag);
* @param feature a feature to lookup (example: 'TCP4' or 'UDP4')
* @return 1 if 'feature' supported, or 0 otherwise
*/
extern int user_have_feature_cast_support(struct hub_user* user, char feature[4]);
extern int user_have_feature_cast_support(struct user* user, char feature[4]);
/**
* Set feature cast support for feature.
@@ -252,38 +258,12 @@ extern int user_have_feature_cast_support(struct hub_user* user, char feature[4]
* @param feature a feature to lookup (example: 'TCP4' or 'UDP4')
* @return 1 if 'feature' supported, or 0 otherwise
*/
extern int user_set_feature_cast_support(struct hub_user* u, char feature[4]);
extern int user_set_feature_cast_support(struct user* u, char feature[4]);
/**
* Remove all feature cast support features.
*/
extern void user_clear_feature_cast_support(struct hub_user* u);
/**
* Mark the user with a want-write flag, meaning it should poll for writability.
*/
extern void user_net_io_want_write(struct hub_user* user);
/**
* Mark the user with a want read flag, meaning it should poll for readability.
*/
extern void user_net_io_want_read(struct hub_user* user);
/**
* Set timeout for connetion.
* @param seconds the number of seconds into the future.
*/
extern void user_set_timeout(struct hub_user* user, int seconds);
/**
* Reset the last-write timer.
*/
extern void user_reset_last_write(struct hub_user* user);
/**
* Reset the last-write timer.
*/
extern void user_reset_last_read(struct hub_user* user);
extern void user_clear_feature_cast_support(struct user* u);

View File

@@ -19,8 +19,6 @@
#include "uhub.h"
#define USERMANAGER_TIMER
/*
* This callback function is used to clear user objects from the userlist.
* Should only be used in uman_shutdown().
@@ -29,7 +27,7 @@ static void clear_user_list_callback(void* ptr)
{
if (ptr)
{
struct hub_user* u = (struct hub_user*) ptr;
struct user* u = (struct user*) ptr;
/* Mark the user as already being disconnected.
* This prevents the hub from trying to send
@@ -61,7 +59,7 @@ void uman_update_stats(struct hub_info* hub)
void uman_print_stats(struct hub_info* hub)
{
LOG_INFO("Statistics users=%zu (peak_users=%zu), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
hub_log(log_info, "Statistics users=%zu (peak_users=%zu), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
hub->users->count,
hub->users->count_peak,
(int) hub->stats.net_tx / 1024,
@@ -85,19 +83,19 @@ static void timer_statistics(int fd, short ev, void *arg)
int uman_init(struct hub_info* hub)
{
struct hub_user_manager* users = NULL;
struct user_manager* users = NULL;
#ifdef USERMANAGER_TIMER
struct timeval timeout = { TIMEOUT_STATS, 0 };
#endif
if (!hub)
return -1;
users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
if (!users)
return -1;
users->list = list_create();
users->sids = sid_pool_create(net_get_max_sockets());
users->free_sid = 1;
if (!users->list)
{
@@ -108,12 +106,9 @@ int uman_init(struct hub_info* hub)
hub->users = users;
#ifdef USERMANAGER_TIMER
if (hub->evbase)
{
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
}
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
#endif // 0
return 0;
}
@@ -125,8 +120,7 @@ int uman_shutdown(struct hub_info* hub)
return -1;
#ifdef USERMANAGER_TIMER
if (evtimer_pending(&hub->ev_timer, 0))
event_del(&hub->ev_timer);
event_del(&hub->ev_timer);
#endif
if (hub->users->list)
@@ -134,7 +128,6 @@ int uman_shutdown(struct hub_info* hub)
list_clear(hub->users->list, &clear_user_list_callback);
list_destroy(hub->users->list);
}
sid_pool_destroy(hub->users->sids);
hub_free(hub->users);
hub->users = 0;
@@ -142,7 +135,7 @@ int uman_shutdown(struct hub_info* hub)
}
int uman_add(struct hub_info* hub, struct hub_user* user)
int uman_add(struct hub_info* hub, struct user* user)
{
if (!hub || !user)
return -1;
@@ -161,21 +154,13 @@ int uman_add(struct hub_info* hub, struct hub_user* user)
return 0;
}
int uman_remove(struct hub_info* hub, struct hub_user* user)
int uman_remove(struct hub_info* hub, struct user* user)
{
if (!hub || !user)
return -1;
list_remove(hub->users->list, user);
if (hub->users->count > 0)
{
hub->users->count--;
}
else
{
assert(!"negative count!");
}
hub->users->count--;
hub->users->shared_size -= user->limits.shared_size;
hub->users->shared_files -= user->limits.shared_files;
@@ -186,81 +171,70 @@ int uman_remove(struct hub_info* hub, struct hub_user* user)
}
struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid)
struct user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid)
{
return sid_lookup(hub->users->sids, sid);
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users */
while (user)
{
if (user->id.sid == sid)
return user;
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
struct hub_user* uman_get_user_by_cid(struct hub_info* hub, const char* cid)
struct user* uman_get_user_by_cid(struct hub_info* hub, const char* cid)
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.cid, cid) == 0)
return user;
user = (struct hub_user*) list_get_next(hub->users->list);
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick)
struct user* uman_get_user_by_nick(struct hub_info* hub, const char* nick)
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.nick, nick) == 0)
return user;
user = (struct hub_user*) list_get_next(hub->users->list);
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range)
{
size_t num = 0;
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (ip_in_range(&user->net.ipaddr, range))
{
list_append(users, user);
num++;
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
return num;
}
int uman_send_user_list(struct hub_info* hub, struct hub_user* target)
int uman_send_user_list(struct user* target)
{
int ret = 1;
user_flag_set(target, flag_user_list);
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on INF or PAS msg */
struct user* user = (struct user*) list_get_first(target->hub->users->list); /* iterate users - only on INF or PAS msg */
while (user)
{
if (user_is_logged_in(user))
{
ret = route_to_user(hub, target, user->info);
ret = route_to_user(target, user->info);
if (!ret)
break;
}
user = (struct hub_user*) list_get_next(hub->users->list);
user = (struct user*) list_get_next(user->hub->users->list);
}
#if 0
FIXME: FIXME FIXME handle send queue excess
if (!target->send_queue_size)
{
user_flag_unset(target, flag_user_list);
}
#endif
return ret;
}
void uman_send_quit_message(struct hub_info* hub, struct hub_user* leaving)
void uman_send_quit_message(struct user* leaving)
{
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));
@@ -269,15 +243,28 @@ void uman_send_quit_message(struct hub_info* hub, struct hub_user* leaving)
{
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
}
route_to_all(hub, command);
route_to_all(leaving->hub, command);
adc_msg_free(command);
}
sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user)
sid_t uman_get_free_sid(struct hub_info* hub)
{
sid_t sid = sid_alloc(hub->users->sids, user);
user->id.sid = sid;
return sid;
#if 0
struct user* user;
user = (struct user*) list_get_first(hub->users->list); /* iterate normal users */
while (user)
{
if (user->sid == hub->users->free_sid)
{
hub->users->free_sid++;
if (hub->users->free_sid >= SID_MAX) hub->users->free_sid = 1;
break;
}
user = (struct user*) list_get_next(hub->users->list);
}
#endif
return hub->users->free_sid++;
}

View File

@@ -20,11 +20,11 @@
#ifndef HAVE_UHUB_USER_MANAGER_H
#define HAVE_UHUB_USER_MANAGER_H
struct hub_user_manager
struct user_manager
{
size_t count; /**<< "Number of all fully connected and logged in users" */
size_t count_peak; /**<< "Peak number of users" */
struct sid_pool* sids;
sid_t free_sid; /**<< "The next available SID." */
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 users" */
@@ -56,7 +56,7 @@ extern void uman_print_stats(struct hub_info* hub);
* @param hub The hub to add the user to
* @param user The user to be added to the hub.
*/
extern int uman_add(struct hub_info* hub, struct hub_user* user);
extern int uman_add(struct hub_info* hub, struct user* user);
/**
* Remove a user from the user manager.
@@ -65,12 +65,12 @@ extern int uman_add(struct hub_info* hub, struct hub_user* user);
*
* @return 0 if successfully removed, -1 if error.
*/
extern int uman_remove(struct hub_info* hub, struct hub_user* user);
extern int uman_remove(struct hub_info* hub, struct user* user);
/**
* Returns and allocates an unused session ID (SID).
*/
extern sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user);
extern sid_t uman_get_free_sid(struct hub_info* hub);
/**
* Lookup a user based on the session ID (SID).
@@ -85,26 +85,19 @@ extern sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user);
*
* @return a user if found, or NULL if not found
*/
extern struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid);
extern struct user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid);
/**
* Lookup a user based on the client ID (CID).
* @return a user if found, or NULL if not found
*/
extern struct hub_user* uman_get_user_by_cid(struct hub_info* hub, const char* cid);
extern struct user* uman_get_user_by_cid(struct hub_info* hub, const char* cid);
/**
* Lookup a user based on the nick name.
* @return a user if found, or NULL if not found
*/
extern struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick);
/**
* Lookup users based on an ip address range.
*
* @return The number of users matching the addressess, or -1 on error (mask is wrong).
*/
extern size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range);
extern struct user* uman_get_user_by_nick(struct hub_info* hub, const char* nick);
/**
* Send the user list of connected clients to 'user'.
@@ -112,13 +105,13 @@ extern size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* us
*
* @return 1 if sending the user list succeeded, 0 otherwise.
*/
extern int uman_send_user_list(struct hub_info* hub, struct hub_user* user);
extern int uman_send_user_list(struct user* user);
/**
* Send a quit message to all connected users when 'user' is
* leaving the hub (for whatever reason).
*/
extern void uman_send_quit_message(struct hub_info* hub, struct hub_user* user);
extern void uman_send_quit_message(struct user* user);
#endif /* HAVE_UHUB_USER_MANAGER_H */

View File

@@ -1,48 +0,0 @@
#!/usr/bin/perl -w
# Setup using inetd/xinetd or similar.
# In /etc/inetd.conf add:
# 1511 stream tcp nowait nobody /usr/bin/adc-redirector adc://target:port
#
# Change port to whatever you want.
# Make sure the path and the target:port is correct, then you should be good
# to go!
use strict;
use IO::Handle;
autoflush STDIN;
autoflush STDOUT;
my $target = $ARGV[0];
eval
{
local %SIG;
$SIG{ALRM}= sub { exit 0; };
alarm 30;
};
while (my $line = <STDIN>)
{
chomp($line);
if ($line =~ /^HSUP /)
{
print "ISUP ADBASE ADPING ADTIGR\n";
print "ISID AAAX\n";
print "IINF CT32 NIRedirector VEadc-redirector/0.1\n";
next;
}
if ($line =~ /^BINF /)
{
print "$line\n";
print "IMSG This\\sserver\\shas\\smoved\\sto:\\s" . $target . "\n";
print "IMSG You\\sare\\sbeing\\sredirected...\n";
print "IQUI AAAX RD" . $target . "\n";
alarm 5;
}
}
alarm 0;

View File

@@ -2,14 +2,12 @@
#define PRODUCT "uHub"
#endif
#ifndef GIT_REVISION
#define REVISION ""
#else
#define REVISION " (git: " GIT_REVISION ")"
#ifndef PRODUCT_TITLE
#define PRODUCT_TITLE "(micro-Hub)"
#endif
#ifndef VERSION
#define VERSION "0.3.0-rc4" REVISION
#define VERSION "0.2.9-rc1"
#endif
#ifndef COPYRIGHT