Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2da49d41a | ||
|
|
4666311516 | ||
|
|
1f24bd6812 | ||
|
|
0e1cd903da | ||
|
|
4931dc5dcb | ||
|
|
077bffd74f | ||
|
|
cfb8a9f322 | ||
|
|
653cfb285e | ||
|
|
053fb30192 | ||
|
|
9bd0286c01 | ||
|
|
b78d48795b | ||
|
|
9b58ba6516 | ||
|
|
f322fbb197 | ||
|
|
80348044c3 | ||
|
|
31d4b0f0b1 | ||
|
|
10615a9a1a | ||
|
|
7b44036480 | ||
|
|
112fa2f845 | ||
|
|
945c6be14c | ||
|
|
099ed6dbe2 | ||
|
|
444f991f44 | ||
|
|
b125ffe3c1 | ||
|
|
76b84499bc | ||
|
|
6358c7f9cd | ||
|
|
041ce7a1fb | ||
|
|
78bb1d3527 | ||
|
|
48f3cae22b | ||
|
|
817250c528 | ||
|
|
f176e790e2 | ||
|
|
367871e476 | ||
|
|
2ac5cc19cb | ||
|
|
6e5d28c2d4 | ||
|
|
5048ff9ae5 | ||
|
|
36a07e3f7e | ||
|
|
e281f61472 | ||
|
|
bb27ff617c | ||
|
|
dc90245ade | ||
|
|
0ec4913e15 | ||
|
|
61d639bfa2 | ||
|
|
adeaf23f9c | ||
|
|
03d3ffd20f | ||
|
|
bbae2603b0 | ||
|
|
5f0c84f46a | ||
|
|
b02618d19c | ||
|
|
927faf70fc | ||
|
|
4a173bf066 | ||
|
|
abd097acf0 | ||
|
|
3fdbccb028 | ||
|
|
3db2ec5e22 | ||
|
|
e68cbd0cde | ||
|
|
98bffd93e9 | ||
|
|
e53119e92c | ||
|
|
ee0ea5a427 | ||
|
|
aa7be1dc4b | ||
|
|
0ef248759c | ||
|
|
5b5d9faf96 | ||
|
|
1f7f6a43f9 | ||
|
|
3cf005a08e | ||
|
|
f3c5fced47 | ||
|
|
9c49f07826 | ||
|
|
0b59941102 | ||
|
|
5f3f2d4f4d | ||
|
|
a3d4c8dbc3 | ||
|
|
7e3a26b0f3 | ||
|
|
9ebb38ae15 | ||
|
|
5b29a3b403 | ||
|
|
75c4272a1b | ||
|
|
f272280faf | ||
|
|
b1d4b1288f | ||
|
|
ddba669af0 | ||
|
|
2ad2b66db3 | ||
|
|
ca33461851 | ||
|
|
4abdc3edbd | ||
|
|
90078ad4b6 | ||
|
|
3bd5c36455 | ||
|
|
8f0943621e | ||
|
|
155350b61b | ||
|
|
1c58120c03 | ||
|
|
1d9acece34 | ||
|
|
57fd872f14 | ||
|
|
ca7544df9b | ||
|
|
c7777e2624 | ||
|
|
b2d543d433 | ||
|
|
ff47281197 | ||
|
|
ddc91d1640 | ||
|
|
0d084a5e14 | ||
|
|
e6e26a02e7 | ||
|
|
ea3cd1bd90 | ||
|
|
7f24238ab5 | ||
|
|
1d2d4e74f6 | ||
|
|
5250fdaf57 | ||
|
|
7ddfd52dc7 | ||
|
|
513ab422f2 | ||
|
|
0eb91763fa | ||
|
|
507f429035 | ||
|
|
b1ab64242e | ||
|
|
8b90f79bac | ||
|
|
8f7cc0b7a7 | ||
|
|
4812a5968b | ||
|
|
8b5bfdd922 | ||
|
|
860310caff | ||
|
|
8167d79f5a | ||
|
|
9706a0a501 | ||
|
|
9309c925d3 | ||
|
|
9a3a5bc2de | ||
|
|
e382e24337 | ||
|
|
be4ff1d8cc | ||
|
|
aa18ac047d | ||
|
|
e120d5c76d | ||
|
|
6853e92f89 | ||
|
|
1dbf2640d2 | ||
|
|
caec28f63f | ||
|
|
5ea5efb875 | ||
|
|
326fcc467c | ||
|
|
078470ce64 | ||
|
|
82ac450b4b | ||
|
|
b4f24b21f9 | ||
|
|
968266b22f | ||
|
|
548867de10 | ||
|
|
953db2dcbc | ||
|
|
6e4ac1355f | ||
|
|
604364ffa5 | ||
|
|
6cc1af5671 | ||
|
|
15e2053699 | ||
|
|
df1e832a3c | ||
|
|
4c4cb4fb36 | ||
|
|
e49f9d4d30 | ||
|
|
e73a931243 | ||
|
|
ae017af758 | ||
|
|
7a02f92a4c | ||
|
|
adeebb92a0 | ||
|
|
26f1864c1f | ||
|
|
c14fa3c3a9 | ||
|
|
dfd2191103 | ||
|
|
0042344054 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*~
|
||||
*.o
|
||||
145
GNUmakefile
145
GNUmakefile
@@ -1,6 +1,6 @@
|
||||
##
|
||||
## Makefile for uhub (Use GNU make)
|
||||
## Copyright (C) 2007-2008, Jan Vidar Krey <janvidar@extatic.org>
|
||||
## Copyright (C) 2007-2009, Jan Vidar Krey <janvidar@extatic.org>
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
@@ -21,6 +21,9 @@ ifeq ($(OS), Windows_NT)
|
||||
WINDOWS ?= YES
|
||||
endif
|
||||
|
||||
|
||||
CFLAGS += -I./src/
|
||||
|
||||
ifeq ($(WINDOWS),YES)
|
||||
USE_BIGENDIAN := NO
|
||||
LDLIBS += -lws2_32
|
||||
@@ -29,6 +32,7 @@ UHUB_PREFIX ?= c:/uhub/
|
||||
CFLAGS += -mno-cygwin
|
||||
LDFLAGS += -mno-cygwin
|
||||
BIN_EXT ?= .exe
|
||||
GIT_REVISION ?= NO
|
||||
else
|
||||
DESTDIR ?= /
|
||||
UHUB_CONF_DIR ?= $(DESTDIR)/etc/uhub
|
||||
@@ -60,17 +64,15 @@ else
|
||||
MSG_CLEAN="Clean as a whistle"
|
||||
endif
|
||||
|
||||
|
||||
|
||||
|
||||
CFLAGS += -I/source/libevent
|
||||
LDFLAGS += -L/source/libevent
|
||||
|
||||
-include release_setup.mk
|
||||
ifeq ($(RELEASE),YES)
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
CFLAGS += -O3 -DNDEBUG
|
||||
GIT_REVISION ?= NO
|
||||
else
|
||||
CFLAGS += -g -DDEBUG
|
||||
CFLAGS += -ggdb -DDEBUG
|
||||
GIT_REVISION ?= YES
|
||||
endif
|
||||
|
||||
ifeq ($(STACK_PROTECT),YES)
|
||||
@@ -127,56 +129,68 @@ 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/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/route.c \
|
||||
src/sid.c \
|
||||
src/tiger.c \
|
||||
src/user.c \
|
||||
src/usermanager.c
|
||||
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
|
||||
|
||||
uhub_SOURCES := src/main.c
|
||||
uhub_SOURCES := src/core/main.c
|
||||
|
||||
adcrush_SOURCES := src/adcrush.c
|
||||
adcrush_SOURCES := src/tools/adcrush.c
|
||||
|
||||
admin_SOURCES := src/admin.c
|
||||
|
||||
uhub_HEADERS := \
|
||||
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/route.h \
|
||||
src/sid.h \
|
||||
src/tiger.h \
|
||||
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/uhub.h \
|
||||
src/user.h \
|
||||
src/usermanager.h
|
||||
src/core/user.h \
|
||||
src/core/usermanager.h
|
||||
|
||||
autotest_SOURCES := \
|
||||
autotest/test_message.tcc \
|
||||
@@ -187,6 +201,7 @@ autotest_SOURCES := \
|
||||
autotest/test_hub.tcc \
|
||||
autotest/test_misc.tcc \
|
||||
autotest/test_tiger.tcc \
|
||||
autotest/test_usermanager.tcc \
|
||||
autotest/test_eventqueue.tcc
|
||||
|
||||
autotest_OBJECTS = autotest.o
|
||||
@@ -195,49 +210,46 @@ 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)
|
||||
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_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 $@.tmp $^ && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_CC) $(CC) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
all: $(uhub_BINARY) $(PCH)
|
||||
|
||||
$(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(admin_BINARY): $(PCH) $(LIBUHUB) $(admin_OBJECTS)
|
||||
$(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(LIBUHUB): $(libuhub_OBJECTS)
|
||||
$(MSG_AR) $(AR) rc $@.tmp $^ && \
|
||||
$(RANLIB) $@.tmp && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@
|
||||
|
||||
ifeq ($(USE_PCH),YES)
|
||||
$(PCH): $(uhub_HEADERS)
|
||||
$(MSG_PCH) $(CC) $(CFLAGS) -o $@.tmp $(PCHSRC) && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC)
|
||||
endif
|
||||
|
||||
autotest.c: $(autotest_SOURCES)
|
||||
$(shell exotic --standalone $(autotest_SOURCES) > $@)
|
||||
|
||||
$(autotest_OBJECTS): autotest.c
|
||||
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@.tmp $< && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@ $<
|
||||
|
||||
$(autotest_BINARY): $(autotest_OBJECTS) $(LIBUHUB)
|
||||
$(MSG_LD) $(CC) -o $@.tmp $^ $(LDFLAGS) $(LDLIBS) && \
|
||||
$(MV) $@.tmp $@
|
||||
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
autotest: $(autotest_BINARY)
|
||||
@./$(autotest_BINARY) -s -f
|
||||
@@ -263,5 +275,4 @@ clean:
|
||||
@rm -rf $(libuhub_OBJECTS) $(PCH) *~ core $(uhub_BINARY) $(LIBUHUB) $(all_OBJECTS) && \
|
||||
echo $(MSG_CLEAN)
|
||||
|
||||
-include release_targets.mk
|
||||
|
||||
|
||||
@@ -79,25 +79,30 @@ function export_sources
|
||||
|
||||
rm -Rf ${PACKAGE}/admin
|
||||
package_zips ${PACKAGE_SRC} ${PACKAGE}
|
||||
|
||||
|
||||
rm -Rf ${PACKAGE};
|
||||
cp ChangeLog ChangeLog-${VERSION}
|
||||
}
|
||||
|
||||
function build_binaries
|
||||
{
|
||||
if [ ! -d ${PACKAGE} ]; then
|
||||
export_source_directory
|
||||
fi
|
||||
|
||||
cd ${PACKAGE}
|
||||
${MAKE} ${MAKEARGS} RELEASE=YES
|
||||
cd ..
|
||||
|
||||
if [ ! -x ${PACKAGE}/${BINARY} ]; then
|
||||
echo "Build failed, no binary found..."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function export_binaries
|
||||
{
|
||||
if [ ! -d ${PACKAGE} ]; then
|
||||
export_source_directory
|
||||
fi
|
||||
|
||||
cd ${PACKAGE}
|
||||
${MAKE} ${MAKEARGS} RELEASE=YES
|
||||
cd ..
|
||||
|
||||
if [ ! -x ${PACKAGE}/${BINARY} ]; then
|
||||
echo "Packaging failed, no binary found..."
|
||||
exit 1
|
||||
fi
|
||||
build_binaries
|
||||
|
||||
rm -Rf ${PACKAGE}/admin
|
||||
rm -Rf ${PACKAGE}/autotest
|
||||
@@ -111,8 +116,7 @@ function export_binaries
|
||||
rm -f ${PACKAGE}/libuhub*
|
||||
|
||||
package_zips ${PACKAGE_BIN} ${PACKAGE}
|
||||
|
||||
rm -Rf ${PACKAGE};
|
||||
rm -Rf ${PACKAGE}
|
||||
}
|
||||
|
||||
function upload_pkg
|
||||
|
||||
95
admin/make_pkg_deb.sh
Executable file
95
admin/make_pkg_deb.sh
Executable file
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
. admin/common.sh
|
||||
|
||||
export_source_directory
|
||||
build_binaries
|
||||
|
||||
DEB_REVISION=1
|
||||
|
||||
if [ -d deb ]; then
|
||||
rm -Rf deb
|
||||
fi
|
||||
|
||||
mkdir -p \
|
||||
deb/DEBIAN \
|
||||
deb/usr/bin \
|
||||
deb/usr/share/man/man1/ \
|
||||
deb/usr/share/doc/uhub \
|
||||
deb/etc/uhub \
|
||||
|| exit 1
|
||||
|
||||
find deb -type d | xargs chmod 755
|
||||
|
||||
# Copy binaries...
|
||||
cp ${PACKAGE}/${BINARY} deb/usr/bin
|
||||
strip deb/usr/bin/${BINARY}
|
||||
|
||||
# Copy configuration files...
|
||||
cp ${PACKAGE}/doc/uhub.conf deb/etc/uhub
|
||||
cp ${PACKAGE}/doc/users.conf deb/etc/uhub
|
||||
echo "Welcome to uHub" > deb/etc/uhub/motd.txt
|
||||
|
||||
# Copy other files
|
||||
cp ${PACKAGE}/README deb/usr/share/doc/uhub
|
||||
cp ${PACKAGE}/AUTHORS deb/usr/share/doc/uhub
|
||||
gzip -c --best < ${PACKAGE}/ChangeLog > deb/usr/share/doc/uhub/changelog.gz
|
||||
gzip -c --best < ${PACKAGE}/doc/uhub.1 > deb/usr/share/man/man1/uhub.1.gz
|
||||
|
||||
cat > deb/usr/share/doc/uhub/copyright <<EOF
|
||||
uHub - a high performance hub for the ADC peer-to-peer network
|
||||
|
||||
Copyright (C) 2007-2009 Jan Vidar Krey <janvidar@extatic.org>
|
||||
|
||||
uHub is free and open source software, licensed under the
|
||||
GNU General Public License version 3.
|
||||
|
||||
For details, see /usr/share/common-licenses/GPL-3
|
||||
EOF
|
||||
|
||||
gzip -c --best > deb/usr/share/doc/uhub/changelog.Debian.gz <<EOF
|
||||
uhub (${VERSION}) stable; urgency=low
|
||||
|
||||
* See changelog.gz for details.
|
||||
|
||||
-- Jan Vidar Krey <janvidar@extatic.org> `date -R`
|
||||
EOF
|
||||
|
||||
### Write control files
|
||||
cd deb
|
||||
echo "/etc/uhub/uhub.conf" > DEBIAN/conffiles
|
||||
echo "/etc/uhub/users.conf" >> DEBIAN/conffiles
|
||||
echo "/etc/uhub/motd.txt" >> DEBIAN/conffiles
|
||||
|
||||
md5sum `find usr -type f` > DEBIAN/md5sums
|
||||
|
||||
INSTALL_SIZE=`du -s | cut -f 1`
|
||||
|
||||
cat > DEBIAN/control <<EOF
|
||||
Package: uhub
|
||||
Version: ${VERSION}-${DEB_REVISION}
|
||||
Architecture: ${HOST_MACHINE}
|
||||
Maintainer: Jan Vidar Krey <janvidar@extatic.org>
|
||||
Installed-Size: ${INSTALL_SIZE}
|
||||
Depends: libc6 (>= 2.7-1), libevent1 (>= 1.3e-1)
|
||||
Section: net
|
||||
Priority: optional
|
||||
Description: a high performance hub for the ADC peer-to-peer network
|
||||
uHub is a high performance peer-to-peer hub for the ADC network.
|
||||
Its low memory footprint allows it to handle several thousand users
|
||||
on high-end servers, or a small private hub on embedded hardware.
|
||||
.
|
||||
Homepage: http://www.extatic.org/uhub/
|
||||
EOF
|
||||
cd ..
|
||||
|
||||
### Create deb file
|
||||
fakeroot dpkg-deb --build deb
|
||||
mv deb.deb uhub_${VERSION}-${DEB_REVISION}_${HOST_MACHINE}.deb
|
||||
|
||||
### Check for errors
|
||||
lintian uhub_${VERSION}-${DEB_REVISION}_${HOST_MACHINE}.deb
|
||||
|
||||
### Cleanup
|
||||
rm -Rf deb
|
||||
rm -Rf ${PACKAGE}
|
||||
|
||||
@@ -10,8 +10,8 @@ static void create_test_user()
|
||||
if (g_user)
|
||||
return;
|
||||
|
||||
g_user = (struct user*) malloc(sizeof(struct user));
|
||||
memset(g_user, 0, sizeof(struct user));
|
||||
g_user = (struct hub_user*) malloc(sizeof(struct hub_user));
|
||||
memset(g_user, 0, sizeof(struct hub_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_shutdown() != -1);
|
||||
return (net_destroy() != -1);
|
||||
});
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
#define USER_NICK "Friend"
|
||||
#define USER_SID "AAAB"
|
||||
|
||||
static struct user* inf_user = 0;
|
||||
static struct hub_user* inf_user = 0;
|
||||
static struct hub_info* inf_hub = 0;
|
||||
|
||||
extern int hub_handle_info_login(struct user* user, struct adc_message* cmd);
|
||||
extern int hub_handle_info_login(struct hub_info* hub, struct hub_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 user_manager*) hub_malloc_zero(sizeof(struct user_manager));
|
||||
inf_hub->users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
|
||||
inf_hub->users->list = list_create();
|
||||
inf_hub->users->free_sid = 1;
|
||||
inf_hub->users->sids = sid_pool_create(500);
|
||||
|
||||
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));
|
||||
@@ -27,16 +27,23 @@ static void inf_create_hub()
|
||||
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);
|
||||
hub_free(inf_hub->acl);
|
||||
hub_free(inf_hub->config);
|
||||
hub_free(inf_hub);
|
||||
}
|
||||
|
||||
|
||||
static void inf_create_user()
|
||||
{
|
||||
if (inf_user) return;
|
||||
inf_user = (struct user*) hub_malloc_zero(sizeof(struct user));
|
||||
inf_user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
|
||||
inf_user->id.sid = 1;
|
||||
inf_user->sd = -1;
|
||||
inf_user->hub = inf_hub;
|
||||
inf_user->net.connection.sd = -1;
|
||||
inf_user->limits.upload_slots = 1;
|
||||
}
|
||||
|
||||
@@ -55,13 +62,13 @@ EXO_TEST(inf_create_setup,
|
||||
});
|
||||
|
||||
|
||||
|
||||
/* FIXME: MEMORY LEAK - Need to fix hub_handle_info_login */
|
||||
#define CHECK_INF(MSG, EXPECT) \
|
||||
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
|
||||
int ok = hub_handle_info_login(inf_user, msg); \
|
||||
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
|
||||
adc_msg_free(msg); \
|
||||
if (ok != EXPECT) \
|
||||
printf("Expected %d, got %d\n", EXPECT, ok); \
|
||||
if (ok == EXPECT) \
|
||||
user_set_info(inf_user, 0); \
|
||||
return ok == EXPECT;
|
||||
|
||||
|
||||
@@ -106,7 +113,7 @@ EXO_TEST(inf_nick_10, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(inf_user, line, strlen(line));
|
||||
|
||||
adc_msg_add_named_argument(msg, "NI", nick);
|
||||
int ok = hub_handle_info_login(inf_user, msg);
|
||||
int ok = hub_handle_info_login(inf_hub, inf_user, msg);
|
||||
adc_msg_free(msg);
|
||||
if (ok != status_msg_inf_error_nick_not_utf8)
|
||||
printf("Expected %d, got %d\n", status_msg_inf_error_nick_not_utf8, ok);
|
||||
|
||||
@@ -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_ban_record ban6;
|
||||
static struct ip_ban_record ban4;
|
||||
static struct ip_range ban6;
|
||||
static struct ip_range 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 acl_check_ip_range(&addr, &ban4);
|
||||
return ip_in_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_2, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.1", &addr);
|
||||
return acl_check_ip_range(&addr, &ban4);
|
||||
return ip_in_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_3, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.0.255", &addr);
|
||||
return acl_check_ip_range(&addr, &ban4);
|
||||
return ip_in_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_4, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.168.1.0", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban4);
|
||||
return !ip_in_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_ipv4_5, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("192.167.255.255", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban4);
|
||||
return !ip_in_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 acl_check_ip_range(&addr, &ban6);
|
||||
return ip_in_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 acl_check_ip_range(&addr, &ban6);
|
||||
return ip_in_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 acl_check_ip_range(&addr, &ban6);
|
||||
return ip_in_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 acl_check_ip_range(&addr, &ban6);
|
||||
return ip_in_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 !acl_check_ip_range(&addr, &ban6);
|
||||
return !ip_in_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 !acl_check_ip_range(&addr, &ban6);
|
||||
return !ip_in_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 !acl_check_ip_range(&addr, &ban4);
|
||||
return !ip_in_range(&addr, &ban4);
|
||||
});
|
||||
|
||||
EXO_TEST(check_ban_afmix_2, {
|
||||
struct ip_addr_encap addr; ip_convert_to_binary("10.20.30.40", &addr);
|
||||
return !acl_check_ip_range(&addr, &ban6);
|
||||
return !ip_in_range(&addr, &ban6);
|
||||
});
|
||||
|
||||
EXO_TEST(ip4_bitwise_AND_1, {
|
||||
@@ -594,6 +594,28 @@ EXO_TEST(ip6_bitwise_OR_3, {
|
||||
return !strcmp(ip_convert_to_string(&ip6_c), "7777:cccc:3333:1111:ffff:ffff:ffff:1c1c");
|
||||
});
|
||||
|
||||
EXO_TEST(shutdown_network, {
|
||||
return net_shutdown() == 0;
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <uhub.h>
|
||||
static struct user* g_user = 0;
|
||||
static struct hub_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,12 +11,17 @@ static void create_test_user()
|
||||
if (g_user)
|
||||
return;
|
||||
|
||||
g_user = (struct user*) malloc(sizeof(struct user));
|
||||
memset(g_user, 0, sizeof(struct user));
|
||||
g_user = (struct hub_user*) malloc(sizeof(struct hub_user));
|
||||
memset(g_user, 0, sizeof(struct hub_user));
|
||||
memcpy(g_user->id.nick, "exotic-tester", 13);
|
||||
g_user->id.sid = 1;
|
||||
}
|
||||
|
||||
EXO_TEST(adc_message_first, {
|
||||
create_test_user();
|
||||
return g_user != 0;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_1, {
|
||||
struct adc_message* msg = adc_msg_create("IMSG Hello\\sWorld!");
|
||||
int ok = msg != NULL;
|
||||
@@ -30,7 +35,6 @@ EXO_TEST(adc_message_parse_2, {
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_parse_3, {
|
||||
create_test_user();
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAB Hello\\sWorld!", 23);
|
||||
int ok = msg != NULL;
|
||||
adc_msg_free(msg);
|
||||
@@ -508,13 +512,22 @@ EXO_TEST(adc_message_update_3, {
|
||||
return updater2 != NULL;
|
||||
});
|
||||
|
||||
extern void update_user_info(struct user* u, struct adc_message* cmd);
|
||||
|
||||
EXO_TEST(adc_message_update_4, {
|
||||
update_user_info(g_user, updater2);
|
||||
user_update_info(g_user, updater2);
|
||||
return strlen(g_user->info->cache) == 159;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_update_4_cleanup, {
|
||||
adc_msg_free(updater1);
|
||||
updater1 = 0;
|
||||
adc_msg_free(updater2);
|
||||
updater2 = 0;
|
||||
adc_msg_free(g_user->info);
|
||||
g_user->info = 0;
|
||||
return 1;
|
||||
});
|
||||
|
||||
|
||||
EXO_TEST(adc_message_empty_1, {
|
||||
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
|
||||
int ok = adc_msg_is_empty(msg) == 0;
|
||||
@@ -536,3 +549,10 @@ EXO_TEST(adc_message_empty_3, {
|
||||
return ok;
|
||||
});
|
||||
|
||||
EXO_TEST(adc_message_last, {
|
||||
hub_free(g_user);
|
||||
g_user = 0;
|
||||
return g_user == 0;
|
||||
});
|
||||
|
||||
|
||||
|
||||
105
autotest/test_usermanager.tcc
Normal file
105
autotest/test_usermanager.tcc
Normal file
@@ -0,0 +1,105 @@
|
||||
#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;
|
||||
});
|
||||
5
debian/changelog
vendored
5
debian/changelog
vendored
@@ -1,5 +0,0 @@
|
||||
uhub (0.2.6-1) unstable; urgency=low
|
||||
|
||||
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
|
||||
|
||||
-- Jan Vidar Krey <janvidar@extatic.org> Tue, 17 Mar 2009 00:38:12 +0100
|
||||
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
||||
7
|
||||
3
debian/conffiles
vendored
3
debian/conffiles
vendored
@@ -1,3 +0,0 @@
|
||||
etc/uhub/uhub.conf
|
||||
etc/uhub/users.conf
|
||||
etc/uhub/motd.txt
|
||||
15
debian/control
vendored
15
debian/control
vendored
@@ -1,15 +0,0 @@
|
||||
Source: uhub
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Jan Vidar Krey <janvidar@extatic.org>
|
||||
Build-Depends: debhelper (>= 7)
|
||||
Standards-Version: 3.8.1
|
||||
Homepage: http://www.extatic.org/uhub/
|
||||
|
||||
Package: uhub
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: uHub is a high performance peer-to-peer hub for the ADC network.
|
||||
Its low memory footprint allows it to handle several thousand users on high-end servers,
|
||||
or a small private hub on embedded hardware.
|
||||
uHub uses the ADC protocol, and is compatible with DC++, jUCy and other ADC clients.
|
||||
9
debian/copyright
vendored
9
debian/copyright
vendored
@@ -1,9 +0,0 @@
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2008-2009 Jan Vidar Krey <janvidar@extatic.org>
|
||||
|
||||
License:
|
||||
|
||||
Licensed under the GPL version 3,
|
||||
see `/usr/share/common-licenses/GPL-3'.
|
||||
|
||||
1
debian/dirs
vendored
1
debian/dirs
vendored
@@ -1 +0,0 @@
|
||||
usr/bin
|
||||
3
debian/docs
vendored
3
debian/docs
vendored
@@ -1,3 +0,0 @@
|
||||
BUGS
|
||||
README
|
||||
AUTHORS
|
||||
1
debian/files
vendored
1
debian/files
vendored
@@ -1 +0,0 @@
|
||||
uhub_0.2.6-1_amd64.deb net extra
|
||||
157
debian/init.d
vendored
157
debian/init.d
vendored
@@ -1,157 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# skeleton example file to build /etc/init.d/ scripts.
|
||||
# This file should be used to construct scripts for /etc/init.d.
|
||||
#
|
||||
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
|
||||
# Modified for Debian
|
||||
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
|
||||
# Further changes by Javier Fernandez-Sanguino <jfs@debian.org>
|
||||
#
|
||||
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
|
||||
#
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/bin/uhub
|
||||
NAME=uhub
|
||||
DESC=uhub
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
LOGDIR=/var/log/uhub
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
DODTIME=1 # Time to wait for the server to die, in seconds
|
||||
# If this value is set too low you might not
|
||||
# let some servers to die gracefully and
|
||||
# 'restart' will not work
|
||||
|
||||
# Include uhub defaults if available
|
||||
if [ -f /etc/default/uhub ] ; then
|
||||
. /etc/default/uhub
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
running_pid()
|
||||
{
|
||||
# Check if a given process pid's cmdline matches a given name
|
||||
pid=$1
|
||||
name=$2
|
||||
[ -z "$pid" ] && return 1
|
||||
[ ! -d /proc/$pid ] && return 1
|
||||
cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
|
||||
# Is this the expected child?
|
||||
[ "$cmd" != "$name" ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
running()
|
||||
{
|
||||
# Check if the process is running looking at /proc
|
||||
# (works for all users)
|
||||
|
||||
# No pidfile, probably no daemon present
|
||||
[ ! -f "$PIDFILE" ] && return 1
|
||||
# Obtain the pid and check it against the binary name
|
||||
pid=`cat $PIDFILE`
|
||||
running_pid $pid $DAEMON || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
force_stop() {
|
||||
# Forcefully kill the process
|
||||
[ ! -f "$PIDFILE" ] && return
|
||||
if running ; then
|
||||
kill -15 $pid
|
||||
# Is it really dead?
|
||||
[ -n "$DODTIME" ] && sleep "$DODTIME"s
|
||||
if running ; then
|
||||
kill -9 $pid
|
||||
[ -n "$DODTIME" ] && sleep "$DODTIME"s
|
||||
if running ; then
|
||||
echo "Cannot kill $LABEL (pid=$pid)!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
rm -f $PIDFILE
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $DESC: "
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE \
|
||||
--exec $DAEMON -- $DAEMON_OPTS
|
||||
if running ; then
|
||||
echo "$NAME."
|
||||
else
|
||||
echo " ERROR."
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: "
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
|
||||
--exec $DAEMON
|
||||
echo "$NAME."
|
||||
;;
|
||||
force-stop)
|
||||
echo -n "Forcefully stopping $DESC: "
|
||||
force_stop
|
||||
if ! running ; then
|
||||
echo "$NAME."
|
||||
else
|
||||
echo " ERROR."
|
||||
fi
|
||||
;;
|
||||
reload)
|
||||
#
|
||||
# If the daemon can reload its config files on the fly
|
||||
# for example by sending it SIGHUP, do it here.
|
||||
#
|
||||
# If the daemon responds to changes in its config file
|
||||
# directly anyway, make this a do-nothing entry.
|
||||
#
|
||||
echo "Reloading $DESC configuration files."
|
||||
start-stop-daemon --stop --signal 1 --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON
|
||||
#;;
|
||||
force-reload)
|
||||
#
|
||||
# If the "reload" option is implemented, move the "force-reload"
|
||||
# option to the "reload" entry above. If not, "force-reload" is
|
||||
# just the same as "restart" except that it does nothing if the
|
||||
# daemon isn't already running.
|
||||
# check wether $DAEMON is running. If so, restart
|
||||
start-stop-daemon --stop --test --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON \
|
||||
&& $0 restart \
|
||||
|| exit 0
|
||||
;;
|
||||
restart)
|
||||
echo -n "Restarting $DESC: "
|
||||
start-stop-daemon --stop --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON
|
||||
[ -n "$DODTIME" ] && sleep $DODTIME
|
||||
start-stop-daemon --start --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
|
||||
echo "$NAME."
|
||||
;;
|
||||
status)
|
||||
echo -n "$LABEL is "
|
||||
if running ; then
|
||||
echo "running"
|
||||
else
|
||||
echo " not running."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
39
debian/postinst
vendored
39
debian/postinst
vendored
@@ -1,39 +0,0 @@
|
||||
#!/bin/sh
|
||||
# postinst script for uhub
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <postinst> `abort-remove'
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
37
debian/postrm
vendored
37
debian/postrm
vendored
@@ -1,37 +0,0 @@
|
||||
#!/bin/sh
|
||||
# postrm script for uhub
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <overwriter>
|
||||
# <overwriter-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
35
debian/preinst
vendored
35
debian/preinst
vendored
@@ -1,35 +0,0 @@
|
||||
#!/bin/sh
|
||||
# preinst script for uhub
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <new-preinst> `install'
|
||||
# * <new-preinst> `install' <old-version>
|
||||
# * <new-preinst> `upgrade' <old-version>
|
||||
# * <old-preinst> `abort-upgrade' <new-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
install|upgrade)
|
||||
;;
|
||||
|
||||
abort-upgrade)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "preinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
38
debian/prerm
vendored
38
debian/prerm
vendored
@@ -1,38 +0,0 @@
|
||||
#!/bin/sh
|
||||
# prerm script for uhub
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <prerm> `remove'
|
||||
# * <old-prerm> `upgrade' <new-version>
|
||||
# * <new-prerm> `failed-upgrade' <old-version>
|
||||
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
|
||||
# * <deconfigured's-prerm> `deconfigure' `in-favour'
|
||||
# <package-being-installed> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
remove|upgrade|deconfigure)
|
||||
;;
|
||||
|
||||
failed-upgrade)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "prerm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
91
debian/rules
vendored
91
debian/rules
vendored
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
$(MAKE)
|
||||
#docbook-to-man debian/uhub.sgml > uhub.1
|
||||
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
$(MAKE) clean
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/uhub.
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/uhub install
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs ChangeLog
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
# dh_install
|
||||
# dh_installmenu
|
||||
# dh_installdebconf
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
# dh_python
|
||||
# dh_installinit
|
||||
# dh_installcron
|
||||
# dh_installinfo
|
||||
dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_perl
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
10
debian/uhub.default
vendored
10
debian/uhub.default
vendored
@@ -1,10 +0,0 @@
|
||||
# Defaults for uhub initscript
|
||||
# sourced by /etc/init.d/uhub
|
||||
# installed at /etc/default/uhub by the maintainer scripts
|
||||
|
||||
# Additional options that are passed to the Daemon.
|
||||
ENABLED=1
|
||||
LOGFILE="/var/log/uhug.log"
|
||||
USER=nobody
|
||||
GROUP=nogroup
|
||||
DAEMON_OPTS="-f -l ${LOGFILE} -u ${USER} -g {GROUP}"
|
||||
72
doc/uhub.1
Normal file
72
doc/uhub.1
Normal file
@@ -0,0 +1,72 @@
|
||||
.TH UHUB 1 "March 2009"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
.\" .nh disable hyphenation
|
||||
.\" .hy enable hyphenation
|
||||
.\" .ad l left justify
|
||||
.\" .ad b justify to both left and right margins
|
||||
.\" .nf disable filling
|
||||
.\" .fi enable filling
|
||||
.\" .br insert line break
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
uhub \- a high performance ADC peer-to-peer hub
|
||||
.SH SYNOPSIS
|
||||
.B uhub
|
||||
.RI [ options ]
|
||||
.SH DESCRIPTION
|
||||
uHub is a high performance peer-to-peer hub for the ADC network.
|
||||
Its low memory footprint allows it to handle several thousand users
|
||||
on high-end servers, or a small private hub on embedded hardware.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.BI \^\-v
|
||||
Verbose mode, add more -v's for higher verbosity.
|
||||
.TP
|
||||
.BI \^\-q
|
||||
Quiet mode, if quiet mode is enabled no output or logs are made.
|
||||
.TP
|
||||
.BI \^\-f
|
||||
Fork uhub to background in order to run it as a daemon.
|
||||
.TP
|
||||
.BI \^\-l " logfile"
|
||||
Log messages to the given logfile (default: stderr)
|
||||
.TP
|
||||
.BI \^\-L
|
||||
Log messages to syslog.
|
||||
.TP
|
||||
.BI \^\-c " config"
|
||||
Specify configuration file (default: /etc/uhub/uhub.conf)
|
||||
.TP
|
||||
.BI \^\-C
|
||||
Check configuration files and return. Will print either \"OK\" or \"ERROR\".
|
||||
.TP
|
||||
.BI \^\-s
|
||||
Show all configuration parameters. In a format that is compatible with
|
||||
the configuration files.
|
||||
.TP
|
||||
.BI \^\-S
|
||||
Show all non-default configuration parameters.
|
||||
.TP
|
||||
.BI \^\-h
|
||||
Show the help message.
|
||||
.TP
|
||||
.BI \^\-u " user"
|
||||
Drop privileges and run as the given user.
|
||||
.TP
|
||||
.BI \^\-g " group"
|
||||
Drop privileges and run with the given group permissions.
|
||||
.TP
|
||||
.BI \^\-V
|
||||
Show the version number
|
||||
.SH EXAMPLES
|
||||
To run uhub as a daemon, and log to a file:
|
||||
.TP
|
||||
.B uhub " -f -l /var/log/uhub/uhub.log"
|
||||
.SH AUTHOR
|
||||
This program was written by Jan Vidar Krey <janvidar@extatic.org>
|
||||
.SH "BUG REPORTS"
|
||||
If you find a bug in uhub please report it to
|
||||
.B http://bugs.extatic.org/
|
||||
@@ -12,8 +12,8 @@
|
||||
# 'ban_cid' - banned user by cid
|
||||
|
||||
# Administrator
|
||||
user_admin Dj_Offset:uhub
|
||||
user_op janvidar:password
|
||||
# user_admin userA:password1
|
||||
# user_op userB:password2
|
||||
|
||||
# We don't want users with these names
|
||||
deny_nick Hub-Security
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
struct adc_message* adc_msg_incref(struct adc_message* msg)
|
||||
{
|
||||
if (!msg) return 0;
|
||||
#ifndef ADC_MESSAGE_INCREF
|
||||
msg->references++;
|
||||
return msg;
|
||||
@@ -234,7 +235,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_t length)
|
||||
struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* line, size_t length)
|
||||
{
|
||||
struct adc_message* command = adc_msg_parse(line, length);
|
||||
|
||||
@@ -243,6 +244,7 @@ struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -266,7 +268,7 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
|
||||
|
||||
if (!is_printable_utf8(line, length))
|
||||
{
|
||||
hub_log(log_debug, "Dropped message with non-printable UTF-8 characters.");
|
||||
LOG_DEBUG("Dropped message with non-printable UTF-8 characters.");
|
||||
hub_free(command);
|
||||
return NULL;
|
||||
}
|
||||
@@ -518,7 +520,6 @@ 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);
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef HAVE_UHUB_COMMAND_H
|
||||
#define HAVE_UHUB_COMMAND_H
|
||||
|
||||
struct user;
|
||||
struct hub_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 user* u, const char* string, size_t length);
|
||||
extern struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* string, size_t length);
|
||||
|
||||
/**
|
||||
* This will parse 'string' and return it as a adc_message struct, or
|
||||
130
src/adc/sid.c
Normal file
130
src/adc/sid.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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];
|
||||
}
|
||||
@@ -22,44 +22,19 @@
|
||||
|
||||
#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);
|
||||
|
||||
struct sid_map
|
||||
{
|
||||
struct user* ptr;
|
||||
struct sid_map* next;
|
||||
};
|
||||
extern struct sid_pool* sid_pool_create(sid_t max);
|
||||
extern void sid_pool_destroy(struct sid_pool*);
|
||||
|
||||
/**
|
||||
* 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 sid_t sid_alloc(struct sid_pool*, struct hub_user*);
|
||||
extern void sid_free(struct sid_pool*, sid_t);
|
||||
extern struct hub_user* sid_lookup(struct sid_pool*, sid_t);
|
||||
|
||||
|
||||
|
||||
193
src/commands.c
193
src/commands.c
@@ -1,193 +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"
|
||||
|
||||
typedef int (*command_handler)(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 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 user* user, const char* command)
|
||||
{
|
||||
char temp[64];
|
||||
snprintf(temp, 64, "*** Access denied: \"%s\"", command);
|
||||
send_message(user, temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int command_stats(struct user* user, const char* message)
|
||||
{
|
||||
char temp[128];
|
||||
snprintf(temp, 128, "*** Stats: %zu users, peak: %zu. Network (up/down): %d/%d KB/s, peak: %d/%d KB/s",
|
||||
user->hub->users->count,
|
||||
user->hub->users->count_peak,
|
||||
(int) user->hub->stats.net_tx / 1024,
|
||||
(int) user->hub->stats.net_rx / 1024,
|
||||
(int) user->hub->stats.net_tx_peak / 1024,
|
||||
(int) user->hub->stats.net_rx_peak / 1024);
|
||||
|
||||
send_message(user, temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int command_help(struct user* user, const char* message)
|
||||
{
|
||||
#define MAX_HELP_MSG 1024
|
||||
size_t n;
|
||||
char msg[MAX_HELP_MSG];
|
||||
msg[0] = 0;
|
||||
strcat(msg, "\n*** Available commands:\n");
|
||||
|
||||
for (n = 0; command_handlers[n].prefix; n++)
|
||||
{
|
||||
if (command_handlers[n].cred <= user->credentials)
|
||||
{
|
||||
strcat(msg, command_handlers[n].prefix);
|
||||
strcat(msg, " - ");
|
||||
strcat(msg, command_handlers[n].description);
|
||||
strcat(msg, "\n");
|
||||
}
|
||||
}
|
||||
send_message(user, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_uptime(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), user->hub->tm_started);
|
||||
|
||||
d = D / (24 * 3600);
|
||||
D = D % (24 * 3600);
|
||||
h = D / 3600;
|
||||
D = D % 3600;
|
||||
m = D / 60;
|
||||
|
||||
tmp[0] = 0;
|
||||
strcat(tmp, "*** Uptime: ");
|
||||
|
||||
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));
|
||||
|
||||
send_message(user, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_kick(struct user* user, const char* message)
|
||||
{
|
||||
send_message(user, "*** Kick not implemented!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_reload(struct user* user, const char* message)
|
||||
{
|
||||
send_message(user, "*** Reloading configuration");
|
||||
user->hub->status = hub_status_restart;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_shutdown(struct user* user, const char* message)
|
||||
{
|
||||
send_message(user, "*** Hub shuting down...");
|
||||
user->hub->status = hub_status_shutdown;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int command_version(struct user* user, const char* message)
|
||||
{
|
||||
send_message(user, "*** Powered by " PRODUCT "/" VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_myip(struct user* user, const char* message)
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, 128, "*** Your IP: %s", ip_convert_to_string(&user->ipaddr));
|
||||
send_message(user, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int command_dipatcher(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(user, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
return command_access_denied(user, &command_handlers[n].prefix[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct commands_handler command_handlers[] = {
|
||||
{ "!help", 5, cred_guest, command_help, "Show this help message." },
|
||||
{ "!stats", 6, cred_super, command_stats, "Show hub statistics." },
|
||||
{ "!version", 8, cred_guest, command_version, "Show hub version info." },
|
||||
{ "!uptime", 7, cred_guest, command_uptime, "Display hub uptime info." },
|
||||
{ "!kick", 5, cred_operator, command_kick, "Kick a user" },
|
||||
{ "!reload", 7, cred_admin, command_reload, "Reload configuration files." },
|
||||
{ "!shutdown", 9, cred_admin, command_shutdown, "Shutdown hub." },
|
||||
{ "+myip", 5, cred_guest, command_myip, "Show your own IP." },
|
||||
{ 0, 0, cred_none, command_help, "{ Last dummy option }" }
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
LOG_FATAL("ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_append(list, hub_strdup(data));
|
||||
hub_log(log_debug, "ACL: Deny access for: '%s' (%s)", data, cmd);
|
||||
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 user_access_info* info = 0;
|
||||
struct hub_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)
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
LOG_FATAL("ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = hub_malloc_zero(sizeof(struct user_access_info));
|
||||
info = hub_malloc_zero(sizeof(struct hub_user_access_info));
|
||||
|
||||
if (!info)
|
||||
{
|
||||
hub_log(log_error, "ACL parse error. Out of memory!");
|
||||
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);
|
||||
hub_log(log_debug, "ACL: Added user '%s' (%s)", info->username, get_user_credential_string(info->status));
|
||||
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_ban_record* info)
|
||||
static void add_ip_range(struct linked_list* list, struct ip_range* info)
|
||||
{
|
||||
char buf1[INET6_ADDRSTRLEN+1];
|
||||
char buf2[INET6_ADDRSTRLEN+1];
|
||||
@@ -130,125 +130,44 @@ static void add_ip_range(struct linked_list* list, struct ip_ban_record* 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);
|
||||
}
|
||||
hub_log(log_debug, "ACL: Deny access for: %s-%s", buf1, buf2);
|
||||
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* data1;
|
||||
char* data2;
|
||||
struct ip_ban_record* info = 0;
|
||||
int cidr_bits = 0;
|
||||
|
||||
char* data;
|
||||
struct ip_range* range = 0;
|
||||
|
||||
if (!strncmp(line, cmd, strlen(cmd)))
|
||||
{
|
||||
data1 = &line[strlen(cmd)];
|
||||
data2 = 0;
|
||||
data1[0] = '\0';
|
||||
data1++;
|
||||
|
||||
data1 = strip_white_space(data1);
|
||||
if (!*data1)
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = hub_malloc_zero(sizeof(struct ip_ban_record));
|
||||
|
||||
if (!info)
|
||||
{
|
||||
hub_log(log_error, "ACL parse error. Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract IP-range */
|
||||
data2 = strrchr(data1, '-');
|
||||
if (data2)
|
||||
{
|
||||
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);
|
||||
data = &line[strlen(cmd)];
|
||||
data[0] = '\0';
|
||||
data++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
data = strip_white_space(data);
|
||||
if (!*data)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
LOG_FATAL("ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
range = hub_malloc_zero(sizeof(struct ip_range));
|
||||
|
||||
if (!range)
|
||||
{
|
||||
LOG_ERROR("ACL parse error. Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ip_convert_address_to_range(data, range))
|
||||
{
|
||||
add_ip_range(list, range);
|
||||
return 1;
|
||||
}
|
||||
hub_free(range);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -269,20 +188,16 @@ static int acl_parse_line(char* line, int line_count, void* ptr_data)
|
||||
if (!*line)
|
||||
return 0;
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "acl_parse_line(): '%s'", line);
|
||||
#endif
|
||||
LOG_DEBUG("acl_parse_line(): '%s'", line);
|
||||
line = strip_white_space(line);
|
||||
|
||||
if (!*line)
|
||||
{
|
||||
hub_log(log_fatal, "ACL parse error on line %d", line_count);
|
||||
LOG_FATAL("ACL parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ACL_DEBUG
|
||||
hub_log(log_trace, "acl_parse_line: '%s'", line);
|
||||
#endif
|
||||
LOG_DEBUG("acl_parse_line: '%s'", line);
|
||||
|
||||
ACL_ADD_USER("bot", handle->users, cred_bot);
|
||||
ACL_ADD_USER("user_admin", handle->users, cred_admin);
|
||||
@@ -296,7 +211,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);
|
||||
|
||||
hub_log(log_error, "Unknown ACL command on line %d: '%s'", line_count, line);
|
||||
LOG_ERROR("Unknown ACL command on line %d: '%s'", line_count, line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -315,7 +230,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)
|
||||
{
|
||||
hub_log(log_fatal, "acl_initialize: Out of memory");
|
||||
LOG_FATAL("acl_initialize: Out of memory");
|
||||
|
||||
list_destroy(handle->users);
|
||||
list_destroy(handle->users_denied);
|
||||
@@ -340,7 +255,7 @@ int acl_initialize(struct hub_config* config, struct acl_handle* handle)
|
||||
|
||||
static void acl_free_access_info(void* ptr)
|
||||
{
|
||||
struct user_access_info* info = (struct user_access_info*) ptr;
|
||||
struct hub_user_access_info* info = (struct hub_user_access_info*) ptr;
|
||||
if (info)
|
||||
{
|
||||
hub_free(info->username);
|
||||
@@ -404,16 +319,16 @@ int acl_shutdown(struct acl_handle* handle)
|
||||
}
|
||||
|
||||
|
||||
struct user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name)
|
||||
struct hub_user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name)
|
||||
{
|
||||
struct user_access_info* info = (struct user_access_info*) list_get_first(handle->users);
|
||||
struct hub_user_access_info* info = (struct hub_user_access_info*) list_get_first(handle->users);
|
||||
while (info)
|
||||
{
|
||||
if (strcasecmp(info->username, name) == 0)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
info = (struct user_access_info*) list_get_next(handle->users);
|
||||
info = (struct hub_user_access_info*) list_get_next(handle->users);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -446,19 +361,54 @@ 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_ban_record* info = (struct ip_ban_record*) list_get_first(handle->networks);
|
||||
struct ip_range* info = (struct ip_range*) list_get_first(handle->networks);
|
||||
ip_convert_to_binary(ip_address, &raw);
|
||||
|
||||
while (info)
|
||||
{
|
||||
if (acl_check_ip_range(&raw, info))
|
||||
if (ip_in_range(&raw, info))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
info = (struct ip_ban_record*) list_get_next(handle->networks);
|
||||
info = (struct ip_range*) list_get_next(handle->networks);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -466,71 +416,62 @@ 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_ban_record* info = (struct ip_ban_record*) list_get_first(handle->nat_override);
|
||||
struct ip_range* info = (struct ip_range*) list_get_first(handle->nat_override);
|
||||
ip_convert_to_binary(ip_address, &raw);
|
||||
|
||||
while (info)
|
||||
{
|
||||
if (acl_check_ip_range(&raw, info))
|
||||
if (ip_in_range(&raw, info))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
info = (struct ip_ban_record*) list_get_next(handle->nat_override);
|
||||
info = (struct ip_range*) 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* password_generate_challenge(struct user* user)
|
||||
const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_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->tm_connected, (int) user->id.sid, (int) user->sd);
|
||||
snprintf(buf, 32, "%d%d%d", (int) user->net.tm_connected, (int) user->id.sid, (int) user->net.connection.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 password_verify(struct user* user, const char* password)
|
||||
int acl_password_verify(struct acl_handle* acl, struct hub_user* user, const char* password)
|
||||
{
|
||||
char buf[1024];
|
||||
struct user_access_info* access;
|
||||
struct hub_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 password_invalid;
|
||||
return 0;
|
||||
|
||||
access = acl_get_access_info(user->hub->acl, user->id.nick);
|
||||
access = acl_get_access_info(acl, user->id.nick);
|
||||
if (!access || !access->password)
|
||||
return password_invalid;
|
||||
return 0;
|
||||
|
||||
if (TIGERSIZE+strlen(access->password) >= 1024)
|
||||
return password_invalid;
|
||||
return 0;
|
||||
|
||||
challenge = password_generate_challenge(user);
|
||||
challenge = acl_password_generate_challenge(acl, user);
|
||||
|
||||
base32_decode(challenge, (unsigned char*) raw_challenge, MAX_CID_LEN);
|
||||
|
||||
@@ -541,14 +482,11 @@ int password_verify(struct user* user, const char* password)
|
||||
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 password_ok;
|
||||
return 1;
|
||||
}
|
||||
return password_invalid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,21 +21,9 @@
|
||||
#define HAVE_UHUB_ACL_H
|
||||
|
||||
struct hub_config;
|
||||
struct user;
|
||||
struct hub_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)" */
|
||||
@@ -50,19 +38,13 @@ enum user_credentials
|
||||
|
||||
const char* get_user_credential_string(enum user_credentials cred);
|
||||
|
||||
struct user_access_info
|
||||
struct hub_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 */
|
||||
@@ -77,7 +59,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 user_access_info* acl_get_access_info(struct acl_handle* handle, const char* name);
|
||||
extern struct hub_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);
|
||||
@@ -85,9 +67,19 @@ 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_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info);
|
||||
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 const char* password_generate_challenge(struct user* user);
|
||||
extern int password_verify(struct user* user, const char* password);
|
||||
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);
|
||||
|
||||
#endif /* HAVE_UHUB_ACL_H */
|
||||
551
src/core/commands.c
Normal file
551
src/core/commands.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* 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, "" }
|
||||
};
|
||||
|
||||
@@ -19,17 +19,4 @@
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
#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 user* user, const char* message);
|
||||
extern int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message);
|
||||
@@ -42,7 +42,7 @@
|
||||
else if (strncasecmp(data, "off", 3) == 0) TARGET = 0; \
|
||||
else\
|
||||
{ \
|
||||
hub_log(log_fatal, "Configuration error on line %d: '%s' must be either '1' or '0'", line_count, key); \
|
||||
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) { \
|
||||
hub_log(log_fatal, "Configuration error on line %d: '%s' must be a number", line_count, key); \
|
||||
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) \
|
||||
{ \
|
||||
hub_log(log_warning, "Configuration option %s deprecated and ingnored.", key); \
|
||||
LOG_WARN("Configuration option %s deprecated and ingnored.", key); \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
@@ -116,6 +116,8 @@
|
||||
#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
|
||||
@@ -175,6 +177,8 @@ 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);
|
||||
@@ -245,6 +249,8 @@ 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);
|
||||
@@ -304,7 +310,7 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
|
||||
GET_STR (tls_private_key);
|
||||
|
||||
/* Still here -- unknown directive */
|
||||
hub_log(log_fatal, "Unknown configuration directive: '%s'", key);
|
||||
LOG_ERROR("Unknown configuration directive: '%s'", key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -391,6 +397,8 @@ 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);
|
||||
@@ -460,9 +468,12 @@ static int config_parse_line(char* line, int line_count, void* ptr_data)
|
||||
|
||||
if (!*line) return 0;
|
||||
|
||||
#ifdef CONFIG_DUMP
|
||||
hub_log(log_trace, "config_parse_line(): '%s'", line);
|
||||
#endif
|
||||
LOG_DUMP("config_parse_line(): '%s'", line);
|
||||
|
||||
if (!is_valid_utf8(line))
|
||||
{
|
||||
LOG_WARN("Invalid utf-8 characters on line %d", line_count);
|
||||
}
|
||||
|
||||
if ((pos = strchr(line, '=')) != NULL)
|
||||
{
|
||||
@@ -481,13 +492,11 @@ static int config_parse_line(char* line, int line_count, void* ptr_data)
|
||||
|
||||
if (!*key || !*data)
|
||||
{
|
||||
hub_log(log_fatal, "Configuration parse error on line %d", line_count);
|
||||
LOG_FATAL("Configuration parse error on line %d", line_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DUMP
|
||||
hub_log(log_trace, "config_parse_line: '%s' => '%s'", key, data);
|
||||
#endif
|
||||
LOG_DUMP("config_parse_line: '%s' => '%s'", key, data);
|
||||
|
||||
return apply_config(config, key, data, line_count);
|
||||
}
|
||||
@@ -504,7 +513,7 @@ int read_config(const char* file, struct hub_config* config, int allow_missing)
|
||||
{
|
||||
if (allow_missing && ret == -2)
|
||||
{
|
||||
hub_log(log_debug, "Using default configuration.");
|
||||
LOG_DUMP("Using default configuration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -38,7 +38,10 @@ struct hub_config
|
||||
int max_send_buffer; /**<<< "Max send buffer before disconnect, per user (default: 128K)" */
|
||||
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)" */
|
||||
@@ -51,7 +54,7 @@ struct hub_config
|
||||
int limit_max_share; /**<<< "Limit maximum share size in megabytes (MiB) (0=off, default: 0)" */
|
||||
int limit_min_slots; /**<<< "Limit minimum number of slots open per user (0=off, default: 0)" */
|
||||
int limit_max_slots; /**<<< "Limit maximum number of slots open per user (0=off, default: 0)" */
|
||||
|
||||
|
||||
/* Messages that can be sent to a user */
|
||||
char* msg_hub_full; /**<<< "hub is full" */
|
||||
char* msg_hub_disabled; /**<<< "hub is disabled" */
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifdef EQ_DEBUG
|
||||
static void eq_debug(const char* prefix, struct event_data* data)
|
||||
{
|
||||
printf(">>> %s: %p, id: %x, flags=%d\n", prefix, data, data->id, data->flags);
|
||||
LOG_DUMP(">>> %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
|
||||
{
|
||||
hub_log(log_error, "event_queue_post: OUT OF MEMORY");
|
||||
LOG_ERROR("event_queue_post: OUT OF MEMORY");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,30 +19,26 @@
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
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 ret = 0;
|
||||
struct adc_message* cmd = 0;
|
||||
|
||||
#ifdef NETWORK_DUMP_DEBUG
|
||||
hub_log(log_protocol, "recv %s: %s", sid_to_string(u->id.sid), line);
|
||||
#endif
|
||||
LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);
|
||||
|
||||
if (user_is_disconnecting(u))
|
||||
return -1;
|
||||
|
||||
|
||||
cmd = adc_msg_parse_verify(u, line, length);
|
||||
if (cmd)
|
||||
{
|
||||
switch (cmd->cmd)
|
||||
{
|
||||
case ADC_CMD_HSUP: ret = hub_handle_support(u, cmd); break;
|
||||
case ADC_CMD_HPAS: ret = hub_handle_password(u, cmd); break;
|
||||
case ADC_CMD_BINF: ret = hub_handle_info(u, cmd); break;
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
case ADC_CMD_HCHK: ret = hub_handle_autocheck(u, cmd); break;
|
||||
#endif
|
||||
case ADC_CMD_HSUP: ret = hub_handle_support(hub, u, cmd); break;
|
||||
case ADC_CMD_HPAS: ret = hub_handle_password(hub, u, cmd); break;
|
||||
case ADC_CMD_BINF: ret = hub_handle_info(hub, u, cmd); break;
|
||||
case ADC_CMD_DINF:
|
||||
case ADC_CMD_EINF:
|
||||
case ADC_CMD_FINF:
|
||||
@@ -54,7 +50,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
case ADC_CMD_DMSG:
|
||||
case ADC_CMD_BMSG:
|
||||
case ADC_CMD_FMSG:
|
||||
ret = hub_handle_chat_message(u, cmd);
|
||||
ret = hub_handle_chat_message(hub, u, cmd);
|
||||
break;
|
||||
|
||||
case ADC_CMD_BSCH:
|
||||
@@ -65,7 +61,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
case ADC_CMD_DRCM:
|
||||
case ADC_CMD_DCTM:
|
||||
cmd->priority = -1;
|
||||
if (u->hub->config->chat_only && u->credentials < cred_operator)
|
||||
if (hub->config->chat_only && u->credentials < cred_operator)
|
||||
{
|
||||
/* These below aren't allowed in chat only hubs */
|
||||
break;
|
||||
@@ -74,7 +70,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
default:
|
||||
if (user_is_logged_in(u))
|
||||
{
|
||||
ret = route_message(u, cmd);
|
||||
ret = route_message(hub, u, cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -96,17 +92,16 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_support(struct user* u, struct adc_message* cmd)
|
||||
int hub_handle_support(struct hub_info* hub, struct hub_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 (u->hub->status == hub_status_disabled && u->state == state_protocol)
|
||||
if (hub->status == hub_status_disabled && u->state == state_protocol)
|
||||
{
|
||||
on_login_failure(u, status_msg_hub_disabled);
|
||||
on_login_failure(hub, u, status_msg_hub_disabled);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -145,14 +140,13 @@ int hub_handle_support(struct user* u, struct adc_message* cmd)
|
||||
|
||||
if (ok)
|
||||
{
|
||||
hub_send_handshake(u);
|
||||
if (u->ev_read)
|
||||
event_add(u->ev_read, &timeout);
|
||||
hub_send_handshake(hub, u);
|
||||
user_set_timeout(u, TIMEOUT_HANDSHAKE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disconnect user. Do not send crap during initial handshake! */
|
||||
user_disconnect(u, quit_logon_error);
|
||||
hub_disconnect_user(hub, u, quit_logon_error);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
@@ -161,20 +155,20 @@ int hub_handle_support(struct user* u, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_password(struct user* u, struct adc_message* cmd)
|
||||
int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
|
||||
{
|
||||
char* password = adc_msg_get_argument(cmd, 0);
|
||||
int ret = 0;
|
||||
|
||||
if (u->state == state_verify)
|
||||
{
|
||||
if (password_verify(u, password))
|
||||
if (acl_password_verify(hub->acl, u, password))
|
||||
{
|
||||
on_login_success(u);
|
||||
on_login_success(hub, u);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_login_failure(u, status_msg_auth_invalid_password);
|
||||
on_login_failure(hub, u, status_msg_auth_invalid_password);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
@@ -184,97 +178,80 @@ int hub_handle_password(struct user* u, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
int hub_handle_chat_message(struct user* u, struct adc_message* cmd)
|
||||
int hub_handle_chat_message(struct hub_info* hub, struct hub_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(u, message);
|
||||
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"); */
|
||||
ret = route_message(u, cmd);
|
||||
if (cmd->cache[0] == 'B')
|
||||
hub_chat_history_add(hub, u, cmd);
|
||||
ret = route_message(hub, u, cmd);
|
||||
}
|
||||
|
||||
free(message);
|
||||
hub_free(message);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int on_kick(struct user* u, struct adc_message* cmd)
|
||||
void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
hub_log(log_error, "on_kick() not implemented");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int hub_handle_autocheck(struct user* u, struct adc_message* cmd)
|
||||
{
|
||||
char* port_str = adc_msg_get_argument(cmd, 0);
|
||||
char* token = adc_msg_get_argument(cmd, 1);
|
||||
int port = 0;
|
||||
|
||||
if (!port_str || !token || strlen(token) != 4)
|
||||
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)
|
||||
{
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
return -1;
|
||||
char* msg = list_get_first(hub->chat_history);
|
||||
list_remove(hub->chat_history, msg);
|
||||
hub_free(msg);
|
||||
}
|
||||
|
||||
port = uhub_atoi(port_str);
|
||||
|
||||
if (port == 0 || port > 65535)
|
||||
{
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub_send_autocheck(u, port, token);
|
||||
|
||||
hub_free(port_str);
|
||||
hub_free(token);
|
||||
|
||||
return 0;
|
||||
hub_free(message);
|
||||
hub_free(msg_esc);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void hub_send_autocheck(struct user* u, uint16_t port, const char* token)
|
||||
void hub_chat_history_clear(struct hub_info* hub)
|
||||
{
|
||||
|
||||
list_clear(hub->chat_history, &hub_free);
|
||||
}
|
||||
|
||||
|
||||
void hub_send_support(struct user* u)
|
||||
void hub_send_support(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
if (user_is_connecting(u) || user_is_logged_in(u))
|
||||
{
|
||||
route_to_user(u, u->hub->command_support);
|
||||
route_to_user(hub, u, hub->command_support);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_sid(struct user* u)
|
||||
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
sid_t sid;
|
||||
struct adc_message* command;
|
||||
if (user_is_connecting(u))
|
||||
{
|
||||
command = adc_msg_construct(ADC_CMD_ISID, 10);
|
||||
u->id.sid = user_manager_get_free_sid(u->hub);
|
||||
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
|
||||
route_to_user(u, command);
|
||||
sid = uman_get_free_sid(hub, u);
|
||||
adc_msg_add_argument(command, (const char*) sid_to_string(sid));
|
||||
route_to_user(hub, u, command);
|
||||
adc_msg_free(command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_ping(struct user* user)
|
||||
void hub_send_ping(struct hub_info* hub, struct hub_user* user)
|
||||
{
|
||||
/* This will just send a newline, despite appearing to do more below. */
|
||||
struct adc_message* ping = adc_msg_construct(0, 0);
|
||||
@@ -282,14 +259,14 @@ void hub_send_ping(struct user* user)
|
||||
ping->cache[1] = 0;
|
||||
ping->length = 1;
|
||||
ping->priority = 1;
|
||||
route_to_user(user, ping);
|
||||
route_to_user(hub, user, ping);
|
||||
adc_msg_free(ping);
|
||||
}
|
||||
|
||||
|
||||
void hub_send_hubinfo(struct user* u)
|
||||
void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
struct adc_message* info = adc_msg_copy(u->hub->command_info);
|
||||
struct adc_message* info = adc_msg_copy(hub->command_info);
|
||||
int value = 0;
|
||||
|
||||
if (user_flag_get(u, feature_ping))
|
||||
@@ -301,66 +278,65 @@ void hub_send_hubinfo(struct user* u)
|
||||
NE - Hub Network
|
||||
OW - Hub Owner name
|
||||
*/
|
||||
adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(u->hub)));
|
||||
adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(u->hub)));
|
||||
adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(u->hub)));
|
||||
adc_msg_add_named_argument(info, "SF", uhub_itoa(hub_get_shared_files(u->hub)));
|
||||
adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(hub)));
|
||||
adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(hub)));
|
||||
adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(hub)));
|
||||
adc_msg_add_named_argument(info, "SF", uhub_itoa(hub_get_shared_files(hub)));
|
||||
|
||||
/* Maximum/minimum share size */
|
||||
value = hub_get_max_share(u->hub);
|
||||
value = hub_get_max_share(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XS", uhub_itoa(value));
|
||||
value = hub_get_min_share(u->hub);
|
||||
value = hub_get_min_share(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MS", uhub_itoa(value));
|
||||
|
||||
/* Maximum/minimum upload slots allowed per user */
|
||||
value = hub_get_max_slots(u->hub);
|
||||
value = hub_get_max_slots(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XL", uhub_itoa(value));
|
||||
value = hub_get_min_slots(u->hub);
|
||||
value = hub_get_min_slots(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "ML", uhub_itoa(value));
|
||||
|
||||
/* guest users must be on min/max hubs */
|
||||
value = hub_get_max_hubs_user(u->hub);
|
||||
value = hub_get_max_hubs_user(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XU", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_user(u->hub);
|
||||
value = hub_get_min_hubs_user(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MU", uhub_itoa(value));
|
||||
|
||||
/* registered users must be on min/max hubs */
|
||||
value = hub_get_max_hubs_reg(u->hub);
|
||||
value = hub_get_max_hubs_reg(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XR", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_reg(u->hub);
|
||||
value = hub_get_min_hubs_reg(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MR", uhub_itoa(value));
|
||||
|
||||
/* operators must be on min/max hubs */
|
||||
value = hub_get_max_hubs_op(u->hub);
|
||||
value = hub_get_max_hubs_op(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "XO", uhub_itoa(value));
|
||||
value = hub_get_min_hubs_op(u->hub);
|
||||
value = hub_get_min_hubs_op(hub);
|
||||
if (value) adc_msg_add_named_argument(info, "MO", uhub_itoa(value));
|
||||
|
||||
/* uptime in seconds */
|
||||
adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), u->hub->tm_started)));
|
||||
adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), hub->tm_started)));
|
||||
}
|
||||
|
||||
if (user_is_connecting(u) || user_is_logged_in(u))
|
||||
{
|
||||
route_to_user(u, info);
|
||||
route_to_user(hub, u, info);
|
||||
}
|
||||
adc_msg_free(info);
|
||||
|
||||
/* Only send banner when connecting */
|
||||
if (u->hub->config->show_banner && user_is_connecting(u))
|
||||
if (hub->config->show_banner && user_is_connecting(u))
|
||||
{
|
||||
route_to_user(u, u->hub->command_banner);
|
||||
route_to_user(hub, u, hub->command_banner);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hub_send_handshake(struct user* u)
|
||||
void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
hub_send_support(u);
|
||||
hub_send_sid(u);
|
||||
hub_send_hubinfo(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))
|
||||
{
|
||||
@@ -368,64 +344,60 @@ void hub_send_handshake(struct user* u)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_motd(struct user* u)
|
||||
void hub_send_motd(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
if (u->hub->command_motd)
|
||||
if (hub->command_motd)
|
||||
{
|
||||
route_to_user(u, u->hub->command_motd);
|
||||
route_to_user(hub, u, hub->command_motd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hub_send_password_challenge(struct user* u)
|
||||
void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
|
||||
{
|
||||
struct adc_message* igpa;
|
||||
igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
|
||||
adc_msg_add_argument(igpa, password_generate_challenge(u));
|
||||
adc_msg_add_argument(igpa, acl_password_generate_challenge(hub->acl, u));
|
||||
user_set_state(u, state_verify);
|
||||
route_to_user(u, igpa);
|
||||
route_to_user(hub, 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;
|
||||
hub_log(log_trace, "hub_event_dispatcher: %x (ptr=%p)", message->id, message->ptr);
|
||||
*/
|
||||
struct hub_user* user = (struct hub_user*) message->ptr;
|
||||
assert(hub != NULL);
|
||||
|
||||
switch (message->id)
|
||||
{
|
||||
case UHUB_EVENT_USER_JOIN:
|
||||
{
|
||||
if (user_is_disconnecting((struct user*) message->ptr))
|
||||
if (user_is_disconnecting(user))
|
||||
break;
|
||||
|
||||
if (message->flags)
|
||||
{
|
||||
hub_send_password_challenge((struct user*) message->ptr);
|
||||
hub_send_password_challenge(hub, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_login_success((struct user*) message->ptr);
|
||||
on_login_success(hub, user);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UHUB_EVENT_USER_QUIT:
|
||||
{
|
||||
user_manager_remove((struct user*) message->ptr);
|
||||
send_quit_message((struct user*) message->ptr);
|
||||
on_logout_user((struct user*) message->ptr);
|
||||
user_schedule_destroy((struct user*) message->ptr);
|
||||
uman_remove(hub, user);
|
||||
uman_send_quit_message(hub, user);
|
||||
on_logout_user(hub, user);
|
||||
hub_schedule_destroy_user(hub, user);
|
||||
break;
|
||||
}
|
||||
|
||||
case UHUB_EVENT_USER_DESTROY:
|
||||
{
|
||||
hub_log(log_trace, "hub_event_dispatcher: UHUB_EVENT_USER_DESTROY (ptr=%p)", message->ptr);
|
||||
user_destroy((struct user*) message->ptr);
|
||||
user_destroy(user);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -439,18 +411,15 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message
|
||||
struct hub_info* hub_start_service(struct hub_config* config)
|
||||
{
|
||||
struct hub_info* hub = 0;
|
||||
int server_tcp, ret, ipv6_supported, af;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int server_udp;
|
||||
#endif
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t sockaddr_size;
|
||||
int server_tcp, ret, ipv6_supported, af;
|
||||
char address_buf[INET6_ADDRSTRLEN+1];
|
||||
|
||||
hub = hub_malloc_zero(sizeof(struct hub_info));
|
||||
if (!hub)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to allocate memory for hub");
|
||||
LOG_FATAL("Unable to allocate memory for hub");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -459,9 +428,9 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
||||
ipv6_supported = net_is_ipv6_supported();
|
||||
|
||||
if (ipv6_supported)
|
||||
hub_log(log_debug, "IPv6 supported.");
|
||||
LOG_DEBUG("IPv6 supported.");
|
||||
else
|
||||
hub_log(log_debug, "IPv6 not supported.");
|
||||
LOG_DEBUG("IPv6 not supported.");
|
||||
|
||||
if (ip_convert_address(config->server_bind_addr, config->server_port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
|
||||
{
|
||||
@@ -486,12 +455,13 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
||||
#endif
|
||||
if (!hub->evbase)
|
||||
{
|
||||
hub_log(log_error, "Unable to initialize libevent.");
|
||||
LOG_ERROR("Unable to initialize libevent.");
|
||||
hub_free(hub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub_log(log_info, "Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
|
||||
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());
|
||||
|
||||
server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_tcp == -1)
|
||||
@@ -501,119 +471,52 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
server_udp = net_socket_create(af, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (server_udp == -1)
|
||||
{
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = net_set_reuseaddress(server_tcp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_set_reuseaddress(server_udp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret = net_set_nonblocking(server_tcp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_set_nonblocking(server_udp, 1);
|
||||
if (ret == -1)
|
||||
{
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret = net_bind(server_tcp, (struct sockaddr*) &addr, sockaddr_size);
|
||||
if (ret == -1)
|
||||
{
|
||||
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()));
|
||||
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);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
ret = net_bind(server_udp, (struct sockaddr*) &addr, sockaddr_size);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "hub_start_service(): Unable to bind to UDP 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);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = net_listen(server_tcp, SERVER_BACKLOG);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "hub_start_service(): Unable to listen to socket");
|
||||
LOG_FATAL("hub_start_service(): Unable to listen to socket");
|
||||
event_base_free(hub->evbase);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub->fd_tcp = server_tcp;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
hub->fd_udp = server_udp;
|
||||
#endif
|
||||
hub->config = config;
|
||||
hub->users = NULL;
|
||||
|
||||
if (user_manager_init(hub) == -1)
|
||||
if (uman_init(hub) == -1)
|
||||
{
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -621,61 +524,72 @@ struct hub_info* hub_start_service(struct hub_config* config)
|
||||
event_base_set(hub->evbase, &hub->ev_accept);
|
||||
if (event_add(&hub->ev_accept, NULL) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
uman_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
event_set(&hub->ev_datagram, hub->fd_udp, EV_READ | EV_PERSIST, net_on_packet, hub);
|
||||
event_base_set(hub->evbase, &hub->ev_datagram);
|
||||
if (event_add(&hub->ev_datagram, NULL) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
net_close(server_udp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
|
||||
{
|
||||
user_manager_shutdown(hub);
|
||||
uman_shutdown(hub);
|
||||
hub_free(hub);
|
||||
net_close(server_tcp);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
net_close(server_udp);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
hub_log(log_trace, "hub_shutdown_service()");
|
||||
LOG_TRACE("hub_shutdown_service()");
|
||||
|
||||
event_queue_shutdown(hub->queue);
|
||||
event_del(&hub->ev_accept);
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
event_del(&hub->ev_datagram);
|
||||
net_close(hub->fd_udp);
|
||||
#endif
|
||||
net_close(hub->fd_tcp);
|
||||
user_manager_shutdown(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 ""
|
||||
@@ -685,14 +599,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);
|
||||
@@ -730,13 +644,17 @@ 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)
|
||||
{
|
||||
adc_msg_add_argument(hub->command_banner, "000 Powered\\sby\\s" SERVER);
|
||||
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);
|
||||
}
|
||||
|
||||
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
|
||||
hub_free(server);
|
||||
}
|
||||
|
||||
|
||||
@@ -757,7 +675,7 @@ void hub_free_variables(struct hub_info* hub)
|
||||
*/
|
||||
static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
|
||||
{
|
||||
struct user* lookup = get_user_by_nick(hub, nick);
|
||||
struct hub_user* lookup = uman_get_user_by_nick(hub, nick);
|
||||
if (lookup)
|
||||
{
|
||||
return 1;
|
||||
@@ -771,7 +689,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 user* lookup = get_user_by_cid(hub, cid);
|
||||
struct hub_user* lookup = uman_get_user_by_cid(hub, cid);
|
||||
if (lookup)
|
||||
{
|
||||
return 1;
|
||||
@@ -796,9 +714,9 @@ 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 user* user, enum status_message msg, enum msg_status_level level)
|
||||
void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_message msg, enum msg_status_level level)
|
||||
{
|
||||
struct hub_config* cfg = user->hub->config;
|
||||
struct hub_config* cfg = hub->config;
|
||||
struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
|
||||
if (!cmd) return;
|
||||
char code[4];
|
||||
@@ -853,7 +771,7 @@ void hub_send_status(struct user* user, enum status_message msg, enum msg_status
|
||||
adc_msg_add_argument(cmd, flag);
|
||||
}
|
||||
|
||||
route_to_user(user, cmd);
|
||||
route_to_user(hub, user, cmd);
|
||||
adc_msg_free(cmd);
|
||||
|
||||
}
|
||||
@@ -1016,17 +934,87 @@ size_t hub_get_min_hubs_op(struct hub_info* hub)
|
||||
|
||||
void hub_event_loop(struct hub_info* hub)
|
||||
{
|
||||
#if 0
|
||||
event_dispatch();
|
||||
#endif
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = event_base_loop(hub->evbase, EVLOOP_ONCE);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_DEBUG("event_base_loop returned: %d", (int) ret);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
event_queue_process(hub->queue);
|
||||
}
|
||||
while (hub->status == hub_status_running);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,22 +79,25 @@ 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;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
int fd_udp;
|
||||
#endif
|
||||
struct event ev_accept;
|
||||
struct event ev_timer;
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
struct event ev_datagram;
|
||||
#endif
|
||||
struct hub_stats stats;
|
||||
struct event_queue* queue;
|
||||
struct event_base* evbase;
|
||||
struct hub_config* config;
|
||||
struct user_manager* users;
|
||||
struct hub_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 */
|
||||
@@ -102,6 +105,12 @@ 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;
|
||||
@@ -116,106 +125,104 @@ struct hub_info
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_message(struct user* u, const char* message, size_t length);
|
||||
extern int hub_handle_message(struct hub_info* hub, struct hub_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 user* u, struct adc_message* cmd);
|
||||
extern int hub_handle_support(struct hub_info* hub, struct hub_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 user* u, struct adc_message* cmd);
|
||||
extern int hub_handle_password(struct hub_info* hub, struct hub_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 user* u, struct adc_message* cmd);
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 user* u, struct adc_message* cmd);
|
||||
extern int hub_handle_info_check_nick(struct hub_info* hub, struct hub_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 user* u, struct adc_message* cmd);
|
||||
|
||||
/**
|
||||
* Can only be used by administrators or operators.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_kick(struct user* u, struct adc_message* cmd);
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
/**
|
||||
* Handle incoming autocheck message.
|
||||
*/
|
||||
extern int hub_handle_autocheck(struct user* u, struct adc_message* cmd);
|
||||
#endif
|
||||
extern int hub_handle_info_check_cid(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void hub_send_support(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void hub_send_sid(struct hub_info* hub, struct hub_user* u);
|
||||
|
||||
/**
|
||||
* Send a 'ping' message to user.
|
||||
*/
|
||||
extern void hub_send_ping(struct user* user);
|
||||
extern void hub_send_ping(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u);
|
||||
|
||||
/**
|
||||
* Send handshake. This basically calls
|
||||
* hub_send_support() and hub_send_sid()
|
||||
*/
|
||||
extern void hub_send_handshake(struct user* u);
|
||||
extern void hub_send_handshake(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void hub_send_motd(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u);
|
||||
|
||||
/**
|
||||
* Send an autocheck message to a user.
|
||||
* This is basically a UDP message. The user's client can then determine
|
||||
* if UDP communication works by either hole punching or configuring UPnP.
|
||||
* Sends a status_message to a user.
|
||||
*/
|
||||
extern void hub_send_autocheck(struct user* u, uint16_t port, const char* token);
|
||||
extern void hub_send_status(struct hub_info*, struct hub_user* user, enum status_message msg, enum msg_status_level level);
|
||||
|
||||
/**
|
||||
* This starts the hub.
|
||||
* Allocates memory, initializes the hub based on the configuration,
|
||||
* and returns a hub handle.
|
||||
* This hub handle must be passed to hub_shutdown_service() in order to cleanup before exiting.
|
||||
*
|
||||
* @return a pointer to the hub info.
|
||||
*/
|
||||
extern struct hub_info* hub_start_service(struct hub_config* config);
|
||||
|
||||
@@ -240,12 +247,6 @@ extern void hub_free_variables(struct hub_info* hub);
|
||||
extern const char* hub_get_status_message(struct hub_info* hub, enum status_message msg);
|
||||
extern const char* hub_get_status_message_log(struct hub_info* hub, enum status_message msg);
|
||||
|
||||
|
||||
/**
|
||||
* Sends a status_message to a user.
|
||||
*/
|
||||
extern void hub_send_status(struct user* user, enum status_message msg, enum msg_status_level level);
|
||||
|
||||
/**
|
||||
* Returns the number of logged in users on the hub.
|
||||
*/
|
||||
@@ -342,6 +343,21 @@ 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 */
|
||||
|
||||
96
src/core/hubevent.c
Normal file
96
src/core/hubevent.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@@ -23,22 +23,22 @@
|
||||
/**
|
||||
* This event is triggered whenever a user successfully logs in to the hub.
|
||||
*/
|
||||
extern void on_login_success(struct user* u);
|
||||
extern void on_login_success(struct hub_info* hub, struct hub_user* u);
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a user failed to log in to the hub.
|
||||
*/
|
||||
extern void on_login_failure(struct user* u, enum status_message msg);
|
||||
extern void on_login_failure(struct hub_info* hub, struct hub_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 user* u);
|
||||
extern void on_logout_user(struct hub_info* hub, struct hub_user* u);
|
||||
|
||||
/**
|
||||
* This event is triggered whenever a user changes his/her nickname.
|
||||
*/
|
||||
extern void on_nick_change(struct user* u, const char* nick);
|
||||
extern void on_nick_change(struct hub_info* hub, struct hub_user* u, const char* nick);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_HUB_EVENT_H */
|
||||
213
src/core/hubio.c
Normal file
213
src/core/hubio.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
107
src/core/hubio.h
Normal file
107
src/core/hubio.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -39,9 +39,7 @@ static void remove_server_restricted_flags(struct adc_message* cmd)
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_REFERER);
|
||||
}
|
||||
|
||||
static int user_is_protected(struct user* user);
|
||||
|
||||
static int set_feature_cast_supports(struct user* u, struct adc_message* cmd)
|
||||
static int set_feature_cast_supports(struct hub_user* u, struct adc_message* cmd)
|
||||
{
|
||||
char *it, *tmp;
|
||||
|
||||
@@ -89,7 +87,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 user* user, struct adc_message* cmd)
|
||||
static int check_cid(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
size_t pos;
|
||||
char* cid = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
|
||||
@@ -150,7 +148,7 @@ static int check_cid(struct user* user, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
static int check_required_login_flags(struct user* user, struct adc_message* cmd)
|
||||
static int check_required_login_flags(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
@@ -186,12 +184,12 @@ static int check_required_login_flags(struct user* user, struct adc_message* cmd
|
||||
* remove any wrong address, and replace it with the correct one
|
||||
* as seen by the hub.
|
||||
*/
|
||||
int check_network(struct user* user, struct adc_message* cmd)
|
||||
int check_network(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
const char* address = ip_convert_to_string(&user->ipaddr);
|
||||
const char* address = ip_convert_to_string(&user->net.ipaddr);
|
||||
|
||||
/* Check for NAT override address */
|
||||
if (acl_is_ip_nat_override(user->hub->acl, address))
|
||||
if (acl_is_ip_nat_override(hub->acl, address))
|
||||
{
|
||||
char* client_given_ip = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
|
||||
if (strcmp(client_given_ip, "0.0.0.0") != 0)
|
||||
@@ -222,6 +220,13 @@ int check_network(struct user* user, struct adc_message* cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void strip_network(struct hub_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);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_UDP_PORT);
|
||||
}
|
||||
|
||||
static int nick_length_ok(const char* nick)
|
||||
{
|
||||
@@ -269,7 +274,7 @@ static int nick_is_utf8(const char* nick)
|
||||
}
|
||||
|
||||
|
||||
static int check_nick(struct user* user, struct adc_message* cmd)
|
||||
static int check_nick(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* nick;
|
||||
char* tmp;
|
||||
@@ -317,10 +322,10 @@ static int check_nick(struct user* user, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
static int check_logged_in(struct user* user, struct adc_message* cmd)
|
||||
static int check_logged_in(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
struct user* lookup1 = get_user_by_nick(user->hub, user->id.nick);
|
||||
struct user* lookup2 = get_user_by_cid(user->hub, user->id.cid);
|
||||
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);
|
||||
|
||||
if (lookup1 == user)
|
||||
{
|
||||
@@ -331,20 +336,20 @@ static int check_logged_in(struct user* user, struct adc_message* cmd)
|
||||
{
|
||||
if (lookup1 == lookup2)
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: exact same user is logged in: %s", user->id.nick);
|
||||
user_disconnect(lookup1, quit_ghost_timeout);
|
||||
LOG_DEBUG("check_logged_in: exact same user is logged in: %s", user->id.nick);
|
||||
hub_disconnect_user(hub, lookup1, quit_ghost_timeout);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lookup1)
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: nickname is in use: %s", user->id.nick);
|
||||
LOG_DEBUG("check_logged_in: nickname is in use: %s", user->id.nick);
|
||||
return status_msg_inf_error_nick_taken;
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_debug, "check_logged_in: CID is in use: %s", user->id.cid);
|
||||
LOG_DEBUG("check_logged_in: CID is in use: %s", user->id.cid);
|
||||
return status_msg_inf_error_cid_taken;
|
||||
}
|
||||
}
|
||||
@@ -358,7 +363,7 @@ static int check_logged_in(struct user* user, struct adc_message* cmd)
|
||||
* 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 user* user, struct adc_message* cmd)
|
||||
static int check_user_agent(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* ua_encoded = 0;
|
||||
char* ua = 0;
|
||||
@@ -379,19 +384,19 @@ static int check_user_agent(struct user* user, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
static int check_acl(struct user* user, struct adc_message* cmd)
|
||||
static int check_acl(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
if (acl_is_cid_banned(user->hub->acl, user->id.cid))
|
||||
if (acl_is_cid_banned(hub->acl, user->id.cid))
|
||||
{
|
||||
return status_msg_ban_permanently;
|
||||
}
|
||||
|
||||
if (acl_is_user_banned(user->hub->acl, user->id.nick))
|
||||
if (acl_is_user_banned(hub->acl, user->id.nick))
|
||||
{
|
||||
return status_msg_ban_permanently;
|
||||
}
|
||||
|
||||
if (acl_is_user_denied(user->hub->acl, user->id.nick))
|
||||
if (acl_is_user_denied(hub->acl, user->id.nick))
|
||||
{
|
||||
return status_msg_inf_error_nick_restricted;
|
||||
}
|
||||
@@ -399,7 +404,7 @@ static int check_acl(struct user* user, struct adc_message* cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
static int check_limits(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
char* arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SHARED_SIZE);
|
||||
if (arg)
|
||||
@@ -410,8 +415,8 @@ static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
user->hub->users->shared_size -= user->limits.shared_size;
|
||||
user->hub->users->shared_size += shared_size;
|
||||
hub->users->shared_size -= user->limits.shared_size;
|
||||
hub->users->shared_size += shared_size;
|
||||
}
|
||||
user->limits.shared_size = shared_size;
|
||||
hub_free(arg);
|
||||
@@ -427,8 +432,8 @@ static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
user->hub->users->shared_files -= user->limits.shared_files;
|
||||
user->hub->users->shared_files += shared_files;
|
||||
hub->users->shared_files -= user->limits.shared_files;
|
||||
hub->users->shared_files += shared_files;
|
||||
}
|
||||
user->limits.shared_files = shared_files;
|
||||
hub_free(arg);
|
||||
@@ -480,37 +485,37 @@ static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
|
||||
if (!user_is_protected(user))
|
||||
{
|
||||
if (user->limits.shared_size < hub_get_min_share(user->hub) && hub_get_min_share(user->hub))
|
||||
if (user->limits.shared_size < hub_get_min_share(hub) && hub_get_min_share(hub))
|
||||
{
|
||||
return status_msg_user_share_size_low;
|
||||
}
|
||||
|
||||
if (user->limits.shared_size > hub_get_max_share(user->hub) && hub_get_max_share(user->hub))
|
||||
if (user->limits.shared_size > hub_get_max_share(hub) && hub_get_max_share(hub))
|
||||
{
|
||||
return status_msg_user_share_size_high;
|
||||
}
|
||||
|
||||
if ((user->limits.hub_count_user > hub_get_max_hubs_user(user->hub) && hub_get_max_hubs_user(user->hub)) ||
|
||||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(user->hub) && hub_get_max_hubs_reg(user->hub)) ||
|
||||
(user->limits.hub_count_operator > hub_get_max_hubs_op(user->hub) && hub_get_max_hubs_op(user->hub)) ||
|
||||
(user->limits.hub_count_total > hub_get_max_hubs_total(user->hub) && hub_get_max_hubs_total(user->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(user->hub) && hub_get_min_hubs_user(user->hub)) ||
|
||||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(user->hub) && hub_get_min_hubs_reg(user->hub)) ||
|
||||
(user->limits.hub_count_operator < hub_get_min_hubs_op(user->hub) && hub_get_min_hubs_op(user->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;
|
||||
}
|
||||
|
||||
if (user->limits.upload_slots < hub_get_min_slots(user->hub) && hub_get_min_slots(user->hub))
|
||||
if (user->limits.upload_slots < hub_get_min_slots(hub) && hub_get_min_slots(hub))
|
||||
{
|
||||
return status_msg_user_slots_low;
|
||||
}
|
||||
|
||||
if (user->limits.upload_slots > hub_get_max_slots(user->hub) && hub_get_max_slots(user->hub))
|
||||
if (user->limits.upload_slots > hub_get_max_slots(hub) && hub_get_max_slots(hub))
|
||||
{
|
||||
return status_msg_user_slots_high;
|
||||
}
|
||||
@@ -525,10 +530,10 @@ static int check_limits(struct user* user, struct adc_message* cmd)
|
||||
* 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 user* user, struct adc_message* cmd)
|
||||
static int set_credentials(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct user_access_info* info = acl_get_access_info(user->hub->acl, user->id.nick);
|
||||
struct hub_user_access_info* info = acl_get_access_info(hub->acl, user->id.nick);
|
||||
|
||||
if (info)
|
||||
{
|
||||
@@ -577,85 +582,14 @@ static int set_credentials(struct user* user, struct adc_message* cmd)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
void update_user_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;
|
||||
}
|
||||
|
||||
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 check_is_hub_full(struct user* user)
|
||||
static int check_is_hub_full(struct hub_info* hub, struct hub_user* user)
|
||||
{
|
||||
/*
|
||||
* If hub is full, don't let users in, but we still want to allow
|
||||
* operators and admins to enter the hub.
|
||||
*/
|
||||
if (user->hub->config->max_users && user->hub->users->count >= user->hub->config->max_users && !user_is_protected(user))
|
||||
if (hub->config->max_users && hub->users->count >= hub->config->max_users && !user_is_protected(user))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -663,23 +597,16 @@ static int check_is_hub_full(struct user* user)
|
||||
}
|
||||
|
||||
|
||||
static int check_registered_users_only(struct user* user)
|
||||
static int check_registered_users_only(struct hub_info* hub, struct hub_user* user)
|
||||
{
|
||||
if (user->hub->config->registered_users_only && !user_is_registered(user))
|
||||
if (hub->config->registered_users_only && !user_is_registered(user))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INF_CHECK(FUNC, USER, CMD) \
|
||||
do { \
|
||||
int ret = FUNC(USER, CMD); \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
} while(0)
|
||||
|
||||
static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
|
||||
static int hub_handle_info_common(struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
/* Remove server restricted flags */
|
||||
remove_server_restricted_flags(cmd);
|
||||
@@ -690,9 +617,9 @@ static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hub_handle_info_low_bandwidth(struct user* user, struct adc_message* cmd)
|
||||
static int hub_handle_info_low_bandwidth(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
if (user->hub->config->low_bandwidth_mode)
|
||||
if (hub->config->low_bandwidth_mode)
|
||||
{
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_USER_AGENT);
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_SHARED_FILES);
|
||||
@@ -711,45 +638,64 @@ static int hub_handle_info_low_bandwidth(struct user* user, struct adc_message*
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hub_handle_info_login(struct user* user, struct adc_message* cmd)
|
||||
#define INF_CHECK(FUNC, HUB, USER, CMD) \
|
||||
do { \
|
||||
int ret = FUNC(HUB, USER, CMD); \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
} while(0)
|
||||
|
||||
int hub_perform_login_checks(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
|
||||
{
|
||||
int need_auth = 0;
|
||||
|
||||
/* Make syntax checks. */
|
||||
INF_CHECK(check_required_login_flags, user, cmd);
|
||||
INF_CHECK(check_cid, user, cmd);
|
||||
INF_CHECK(check_nick, user, cmd);
|
||||
INF_CHECK(check_network, user, cmd);
|
||||
INF_CHECK(check_user_agent, user, cmd);
|
||||
INF_CHECK(check_acl, user, cmd);
|
||||
INF_CHECK(check_logged_in, user, cmd);
|
||||
INF_CHECK(check_required_login_flags, hub, user, cmd);
|
||||
INF_CHECK(check_cid, hub, user, cmd);
|
||||
INF_CHECK(check_nick, hub, user, cmd);
|
||||
INF_CHECK(check_network, hub, user, cmd);
|
||||
INF_CHECK(check_user_agent, hub, user, cmd);
|
||||
INF_CHECK(check_acl, hub, user, cmd);
|
||||
INF_CHECK(check_logged_in, hub, user, cmd);
|
||||
|
||||
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 code = 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);
|
||||
|
||||
/* FIXME: This needs some cleaning up */
|
||||
need_auth = set_credentials(user, cmd);
|
||||
|
||||
code = set_credentials(hub, user, cmd);
|
||||
|
||||
/* Note: this must be done *after* set_credentials. */
|
||||
if (check_is_hub_full(user))
|
||||
if (check_is_hub_full(hub, user))
|
||||
{
|
||||
return status_msg_hub_full;
|
||||
}
|
||||
|
||||
if (check_registered_users_only(user))
|
||||
if (check_registered_users_only(hub, user))
|
||||
{
|
||||
return status_msg_hub_registered_users_only;
|
||||
}
|
||||
|
||||
INF_CHECK(check_limits, user, cmd);
|
||||
INF_CHECK(check_limits, hub, user, cmd);
|
||||
|
||||
/* strip off stuff if low_bandwidth_mode is enabled */
|
||||
hub_handle_info_low_bandwidth(user, cmd);
|
||||
hub_handle_info_low_bandwidth(hub, user, cmd);
|
||||
|
||||
/* Set initial user info */
|
||||
user_set_info(user, cmd);
|
||||
|
||||
return need_auth;
|
||||
return code;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -765,7 +711,7 @@ int hub_handle_info_login(struct user* user, struct adc_message* cmd)
|
||||
* - CID/PID (valid, not taken, etc).
|
||||
* - IP addresses (IPv4 and IPv6)
|
||||
*/
|
||||
int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
|
||||
int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct adc_message* cmd_unmodified)
|
||||
{
|
||||
struct adc_message* cmd = adc_msg_copy(cmd_unmodified);
|
||||
if (!cmd) return -1; /* OOM */
|
||||
@@ -789,10 +735,10 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = hub_handle_info_login(user, cmd);
|
||||
int ret = hub_handle_info_login(hub, user, cmd);
|
||||
if (ret < 0)
|
||||
{
|
||||
on_login_failure(user, ret);
|
||||
on_login_failure(hub, user, ret);
|
||||
adc_msg_free(cmd);
|
||||
return -1;
|
||||
}
|
||||
@@ -804,7 +750,7 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
|
||||
post.id = UHUB_EVENT_USER_JOIN;
|
||||
post.ptr = user;
|
||||
post.flags = ret; /* 0 - all OK, 1 - need authentication */
|
||||
event_queue_post(user->hub->queue, &post);
|
||||
event_queue_post(hub->queue, &post);
|
||||
adc_msg_free(cmd);
|
||||
return 0;
|
||||
}
|
||||
@@ -821,20 +767,22 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
|
||||
*/
|
||||
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK))
|
||||
{
|
||||
#if ALLOW_CHANGE_NICK
|
||||
if (!check_nick(user, cmd))
|
||||
#ifdef ALLOW_CHANGE_NICK
|
||||
if (!check_nick(hub, user, cmd))
|
||||
#endif
|
||||
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK);
|
||||
}
|
||||
|
||||
/* FIXME - What if limits are not met ? */
|
||||
check_limits(user, cmd);
|
||||
hub_handle_info_low_bandwidth(user, cmd);
|
||||
update_user_info(user, cmd);
|
||||
check_limits(hub, user, cmd);
|
||||
strip_network(user, cmd);
|
||||
hub_handle_info_low_bandwidth(hub, user, cmd);
|
||||
|
||||
user_update_info(user, cmd);
|
||||
|
||||
if (!adc_msg_is_empty(cmd))
|
||||
{
|
||||
route_message(user, cmd);
|
||||
route_message(hub, user, cmd);
|
||||
}
|
||||
|
||||
adc_msg_free(cmd);
|
||||
@@ -47,7 +47,7 @@ enum nick_status
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
extern int hub_handle_info(struct user* u, const struct adc_message* cmd);
|
||||
extern int hub_handle_info(struct hub_info* hub, struct hub_user* u, const struct adc_message* cmd);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_INF_PARSER_H */
|
||||
@@ -29,6 +29,7 @@ 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;
|
||||
|
||||
|
||||
@@ -41,12 +42,12 @@ void hub_handle_signal(int fd, short events, void* arg)
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT:
|
||||
hub_log(log_info, "Interrupted. Shutting down...");
|
||||
LOG_INFO("Interrupted. Shutting down...");
|
||||
hub->status = hub_status_shutdown;
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
hub_log(log_info, "Terminated. Shutting down...");
|
||||
LOG_INFO("Terminated. Shutting down...");
|
||||
hub->status = hub_status_shutdown;
|
||||
break;
|
||||
|
||||
@@ -58,7 +59,7 @@ void hub_handle_signal(int fd, short events, void* arg)
|
||||
break;
|
||||
|
||||
default:
|
||||
hub_log(log_trace, "hub_handle_signal(): caught unknown signal: %d", signal);
|
||||
LOG_TRACE("hub_handle_signal(): caught unknown signal: %d", signal);
|
||||
hub->status = hub_status_shutdown;
|
||||
break;
|
||||
}
|
||||
@@ -83,9 +84,9 @@ void setup_signal_handlers(struct hub_info* hub)
|
||||
event_base_set(hub->evbase, &signal_events[i]);
|
||||
if (signal_add(&signal_events[i], NULL))
|
||||
{
|
||||
hub_log(log_error, "Error setting signal handler %d", signals[i]);
|
||||
LOG_ERROR("Error setting signal handler %d", signals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown_signal_handlers(struct hub_info* hub)
|
||||
@@ -94,7 +95,7 @@ void shutdown_signal_handlers(struct hub_info* hub)
|
||||
for (i = 0; signals[i]; i++)
|
||||
{
|
||||
signal_del(&signal_events[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
@@ -113,8 +114,8 @@ int main_loop()
|
||||
{
|
||||
if (hub)
|
||||
{
|
||||
hub_log(log_info, "Reloading configuration files...");
|
||||
hub_log(log_debug, "Hub status: %d", (int) hub->status);
|
||||
LOG_INFO("Reloading configuration files...");
|
||||
LOG_DEBUG("Hub status: %d", (int) hub->status);
|
||||
}
|
||||
|
||||
if (read_config(arg_config, &configuration, !arg_have_config) == -1)
|
||||
@@ -157,7 +158,7 @@ int main_loop()
|
||||
hub_shutdown_service(hub);
|
||||
}
|
||||
|
||||
net_shutdown();
|
||||
net_destroy();
|
||||
hub_log_shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -167,21 +168,22 @@ int check_configuration(int dump)
|
||||
{
|
||||
struct hub_config configuration;
|
||||
int ret = read_config(arg_config, &configuration, 0);
|
||||
|
||||
|
||||
if (dump)
|
||||
{
|
||||
dump_config(&configuration, dump > 1);
|
||||
puts("");
|
||||
}
|
||||
|
||||
if (dump)
|
||||
if (ret != -1)
|
||||
{
|
||||
dump_config(&configuration, dump > 1);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
fprintf(stderr, "ERROR\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "OK\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -189,7 +191,7 @@ int check_configuration(int dump)
|
||||
|
||||
void print_version()
|
||||
{
|
||||
fprintf(stdout, "" PRODUCT " " VERSION " " PRODUCT_TITLE "\n");
|
||||
fprintf(stdout, "" PRODUCT " " VERSION "\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);
|
||||
@@ -214,6 +216,7 @@ 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"
|
||||
);
|
||||
@@ -225,7 +228,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:VCsSL")) != -1)
|
||||
while ((opt = getopt(argc, argv, "vqfc:l:hu:g:VCsSLp:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@@ -285,6 +288,10 @@ void parse_command_line(int argc, char** argv)
|
||||
arg_gid = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
arg_pid = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
@@ -328,15 +335,15 @@ int drop_privileges()
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to determine group id, check group name.");
|
||||
LOG_FATAL("Unable to determine group id, check group name.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
ret = setgid(perm_gid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change group id, permission denied.");
|
||||
LOG_FATAL("Unable to change group id, permission denied.");
|
||||
return -1;
|
||||
}
|
||||
gid_ok = 1;
|
||||
@@ -361,31 +368,58 @@ int drop_privileges()
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to determine user id, check user name.");
|
||||
LOG_FATAL("Unable to determine user id, check user name.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!gid_ok) {
|
||||
hub_log(log_trace, "Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid);
|
||||
ret = setgid(perm_gid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change group id, permission denied.");
|
||||
LOG_FATAL("Unable to change group id, permission denied.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
hub_log(log_trace, "Setting user id %d (%s)", (int) perm_uid, arg_uid);
|
||||
LOG_TRACE("Setting user id %d (%s)", (int) perm_uid, arg_uid);
|
||||
ret = setuid(perm_uid);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to change user id, permission denied.");
|
||||
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 */
|
||||
|
||||
|
||||
@@ -406,26 +440,40 @@ int main(int argc, char** argv)
|
||||
ret = fork();
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to fork to background!");
|
||||
LOG_FATAL("Unable to fork to background!");
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* child process */
|
||||
/* child process - detatch from TTY */
|
||||
fclose(stdin);
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* parent process */
|
||||
hub_log(log_debug, "Forked to background\n");
|
||||
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;
|
||||
}
|
||||
|
||||
350
src/core/netevent.c
Normal file
350
src/core/netevent.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,32 +20,15 @@
|
||||
#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);
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
/**
|
||||
* Network callback to receive incoming UDP datagram.
|
||||
*/
|
||||
extern void net_on_packet(int fd, short ev, void *arg);
|
||||
#endif
|
||||
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 */
|
||||
219
src/core/route.c
Normal file
219
src/core/route.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -23,12 +23,17 @@
|
||||
/**
|
||||
* Route a message by sending it to it's final destination.
|
||||
*/
|
||||
extern int route_message(struct user* u, struct adc_message* msg);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Transmit message directly to one user.
|
||||
*/
|
||||
extern int route_to_user(struct user*, struct adc_message* command);
|
||||
extern int route_to_user(struct hub_info* hub, struct hub_user*, struct adc_message* command);
|
||||
|
||||
/**
|
||||
* Broadcast message to all users.
|
||||
@@ -45,7 +50,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 user* user);
|
||||
extern int route_info_message(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_ROUTE_H */
|
||||
375
src/core/user.c
Normal file
375
src/core/user.c
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* 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";
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef HAVE_UHUB_USER_H
|
||||
#define HAVE_UHUB_USER_H
|
||||
|
||||
|
||||
struct hub_info;
|
||||
|
||||
struct hub_iobuf;
|
||||
|
||||
enum user_state
|
||||
{
|
||||
@@ -34,7 +33,6 @@ enum user_state
|
||||
state_disconnected = 5, /**<< "User is disconnected" */
|
||||
};
|
||||
|
||||
|
||||
enum user_flags
|
||||
{
|
||||
feature_base = 0x00000001, /** BASE: Basic configuration (required by all clients) */
|
||||
@@ -52,10 +50,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_nat = 0x40000000, /** nat override enabled */
|
||||
flag_pipeline = 0x40000000, /** Hub message pipelining */
|
||||
flag_nat = 0x80000000, /** nat override enabled */
|
||||
};
|
||||
|
||||
|
||||
enum user_quit_reason
|
||||
{
|
||||
quit_unknown = 0,
|
||||
@@ -72,8 +70,10 @@ 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 user_info
|
||||
struct hub_user_info
|
||||
{
|
||||
sid_t sid; /** session ID */
|
||||
char cid[MAX_CID_LEN+1]; /** global client ID */
|
||||
@@ -85,7 +85,7 @@ struct user_info
|
||||
* as the number of bytes and files shared, and the number of hubs the
|
||||
* user is connected to, etc.
|
||||
*/
|
||||
struct user_counts
|
||||
struct hub_user_limits
|
||||
{
|
||||
uint64_t shared_size; /** Shared size in bytes */
|
||||
size_t shared_files; /** The number of shared files */
|
||||
@@ -96,34 +96,32 @@ struct user_counts
|
||||
size_t hub_count_total; /** The number of hubs connected to in total */
|
||||
};
|
||||
|
||||
struct user
|
||||
struct hub_user_net_io
|
||||
{
|
||||
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 */
|
||||
struct net_connection connection; /** Connection data */
|
||||
struct event timeout; /** timeout handling */
|
||||
struct hub_recvq* recv_queue;
|
||||
struct hub_sendq* send_queue;
|
||||
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 */
|
||||
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 */
|
||||
struct hub_user_limits limits; /** Data used for limitation */
|
||||
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -137,64 +135,69 @@ struct user
|
||||
* @param sd socket descriptor associated with the user
|
||||
* @return User object or NULL if not enough memory is available.
|
||||
*/
|
||||
extern struct user* user_create(struct hub_info* hub, int sd);
|
||||
extern struct hub_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 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);
|
||||
extern void user_destroy(struct hub_user* user);
|
||||
|
||||
/**
|
||||
* This associates a INF message to the user.
|
||||
* If the user already has a INF message associated, then this is
|
||||
* released before setting the new one.
|
||||
*
|
||||
* @param info new inf message (can be NULL)
|
||||
*/
|
||||
extern void user_set_info(struct user* user, struct adc_message* info);
|
||||
extern void user_set_info(struct hub_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);
|
||||
|
||||
/**
|
||||
* Specify a user's state.
|
||||
* NOTE: DON'T, unless you know what you are doing.
|
||||
*/
|
||||
extern void user_set_state(struct user* user, enum user_state);
|
||||
extern void user_set_state(struct hub_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 user* user);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns 1 if the user is in state_protocol, state_identify or state_verify.
|
||||
* Returns 0 otherwise.
|
||||
*/
|
||||
extern int user_is_connecting(struct user* user);
|
||||
extern int user_is_connecting(struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Returns 1 only if the user is in state_cleanup or state_disconnected.
|
||||
*/
|
||||
extern int user_is_disconnecting(struct user* user);
|
||||
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);
|
||||
|
||||
/**
|
||||
* User supports the protocol extension as given in fourcc.
|
||||
@@ -204,7 +207,7 @@ extern int user_is_disconnecting(struct user* user);
|
||||
*
|
||||
* @see enum user_flags
|
||||
*/
|
||||
extern void user_support_add(struct user* user, int fourcc);
|
||||
extern void user_support_add(struct hub_user* user, int fourcc);
|
||||
|
||||
/**
|
||||
* User no longer supports the protocol extension as given in fourcc.
|
||||
@@ -212,26 +215,26 @@ extern void user_support_add(struct user* user, int fourcc);
|
||||
* the hub.
|
||||
* @see enum user_flags
|
||||
*/
|
||||
extern void user_support_remove(struct user* user, int fourcc);
|
||||
extern void user_support_remove(struct hub_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 user* user);
|
||||
extern int user_is_nat_override(struct user* user);
|
||||
extern void user_set_nat_override(struct hub_user* user);
|
||||
extern int user_is_nat_override(struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Set a flag. @see enum user_flags
|
||||
*/
|
||||
extern void user_flag_set(struct user* user, enum user_flags flag);
|
||||
extern void user_flag_unset(struct user* user, enum user_flags flag);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Get a flag. @see enum user_flags
|
||||
*/
|
||||
extern int user_flag_get(struct user* user, enum user_flags flag);
|
||||
extern int user_flag_get(struct hub_user* user, enum user_flags flag);
|
||||
|
||||
/**
|
||||
* Check if a user supports 'feature' for feature casting (basis for 'Fxxx' messages)
|
||||
@@ -241,7 +244,7 @@ extern int user_flag_get(struct 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 user* user, char feature[4]);
|
||||
extern int user_have_feature_cast_support(struct hub_user* user, char feature[4]);
|
||||
|
||||
/**
|
||||
* Set feature cast support for feature.
|
||||
@@ -249,12 +252,38 @@ extern int user_have_feature_cast_support(struct 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 user* u, char feature[4]);
|
||||
extern int user_set_feature_cast_support(struct hub_user* u, char feature[4]);
|
||||
|
||||
/**
|
||||
* Remove all feature cast support features.
|
||||
*/
|
||||
extern void user_clear_feature_cast_support(struct user* u);
|
||||
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);
|
||||
|
||||
|
||||
|
||||
283
src/core/usermanager.c
Normal file
283
src/core/usermanager.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#define USERMANAGER_TIMER
|
||||
|
||||
/*
|
||||
* This callback function is used to clear user objects from the userlist.
|
||||
* Should only be used in uman_shutdown().
|
||||
*/
|
||||
static void clear_user_list_callback(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
struct hub_user* u = (struct hub_user*) ptr;
|
||||
|
||||
/* Mark the user as already being disconnected.
|
||||
* This prevents the hub from trying to send
|
||||
* quit messages to other users.
|
||||
*/
|
||||
u->credentials = cred_none;
|
||||
user_destroy(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uman_update_stats(struct hub_info* hub)
|
||||
{
|
||||
const int factor = TIMEOUT_STATS;
|
||||
struct net_statistics* total;
|
||||
struct net_statistics* intermediate;
|
||||
net_stats_get(&intermediate, &total);
|
||||
|
||||
hub->stats.net_tx = (intermediate->tx / factor);
|
||||
hub->stats.net_rx = (intermediate->rx / factor);
|
||||
hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
|
||||
hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
|
||||
hub->stats.net_tx_total = total->tx;
|
||||
hub->stats.net_rx_total = total->rx;
|
||||
|
||||
net_stats_reset();
|
||||
}
|
||||
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
||||
#ifdef USERMANAGER_TIMER
|
||||
static void timer_statistics(int fd, short ev, void *arg)
|
||||
{
|
||||
struct hub_info* hub = (struct hub_info*) arg;
|
||||
struct timeval timeout = { TIMEOUT_STATS, 0 };
|
||||
uman_update_stats(hub);
|
||||
evtimer_set(&hub->ev_timer, timer_statistics, hub);
|
||||
event_base_set(hub->evbase, &hub->ev_timer);
|
||||
evtimer_add(&hub->ev_timer, &timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int uman_init(struct hub_info* hub)
|
||||
{
|
||||
struct hub_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));
|
||||
if (!users)
|
||||
return -1;
|
||||
|
||||
users->list = list_create();
|
||||
users->sids = sid_pool_create(net_get_max_sockets());
|
||||
|
||||
if (!users->list)
|
||||
{
|
||||
list_destroy(users->list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif // 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uman_shutdown(struct hub_info* hub)
|
||||
{
|
||||
if (!hub || !hub->users)
|
||||
return -1;
|
||||
|
||||
#ifdef USERMANAGER_TIMER
|
||||
if (evtimer_pending(&hub->ev_timer, 0))
|
||||
event_del(&hub->ev_timer);
|
||||
#endif
|
||||
|
||||
if (hub->users->list)
|
||||
{
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uman_add(struct hub_info* hub, struct hub_user* user)
|
||||
{
|
||||
if (!hub || !user)
|
||||
return -1;
|
||||
|
||||
if (user->hub)
|
||||
return -1;
|
||||
|
||||
list_append(hub->users->list, user);
|
||||
hub->users->count++;
|
||||
hub->users->count_peak = MAX(hub->users->count, hub->users->count_peak);
|
||||
|
||||
hub->users->shared_size += user->limits.shared_size;
|
||||
hub->users->shared_files += user->limits.shared_files;
|
||||
|
||||
user->hub = hub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uman_remove(struct hub_info* hub, struct hub_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->shared_size -= user->limits.shared_size;
|
||||
hub->users->shared_files -= user->limits.shared_files;
|
||||
|
||||
user->hub = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid)
|
||||
{
|
||||
return sid_lookup(hub->users->sids, sid);
|
||||
}
|
||||
|
||||
|
||||
struct hub_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 */
|
||||
while (user)
|
||||
{
|
||||
if (strcmp(user->id.cid, cid) == 0)
|
||||
return user;
|
||||
user = (struct hub_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 hub_user* user = (struct hub_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);
|
||||
}
|
||||
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 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 */
|
||||
while (user)
|
||||
{
|
||||
if (user_is_logged_in(user))
|
||||
{
|
||||
ret = route_to_user(hub, target, user->info);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
user = (struct hub_user*) list_get_next(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)
|
||||
{
|
||||
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
|
||||
adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));
|
||||
|
||||
if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
|
||||
{
|
||||
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
|
||||
}
|
||||
route_to_all(hub, command);
|
||||
adc_msg_free(command);
|
||||
}
|
||||
|
||||
|
||||
sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user)
|
||||
{
|
||||
sid_t sid = sid_alloc(hub->users->sids, user);
|
||||
user->id.sid = sid;
|
||||
return sid;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#ifndef HAVE_UHUB_USER_MANAGER_H
|
||||
#define HAVE_UHUB_USER_MANAGER_H
|
||||
|
||||
struct user_manager
|
||||
struct hub_user_manager
|
||||
{
|
||||
size_t count; /**<< "Number of all fully connected and logged in users" */
|
||||
size_t count_peak; /**<< "Peak number of users" */
|
||||
sid_t free_sid; /**<< "The next available SID." */
|
||||
struct sid_pool* sids;
|
||||
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" */
|
||||
@@ -34,55 +34,77 @@ struct user_manager
|
||||
* Initializes the user manager.
|
||||
* @return 0 on success, or -1 if error (out of memory).
|
||||
*/
|
||||
extern int user_manager_init(struct hub_info* hub);
|
||||
extern int uman_init(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Shuts down the user manager.
|
||||
* All users will be disconnected and deleted as part of this.
|
||||
*
|
||||
* @return 0 on success, or -1 in an error occured (hub is invalid).
|
||||
*/
|
||||
extern void user_manager_shutdown(struct hub_info* hub);
|
||||
extern int uman_shutdown(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Generate statistics for logfiles.
|
||||
*/
|
||||
extern void user_manager_update_stats(struct hub_info* hub);
|
||||
extern void user_manager_print_stats(struct hub_info* hub);
|
||||
extern void uman_update_stats(struct hub_info* hub);
|
||||
extern void uman_print_stats(struct hub_info* hub);
|
||||
|
||||
/**
|
||||
* Add a new user to the user manager.
|
||||
* Add a user to the user manager.
|
||||
*
|
||||
* @param hub The hub to add the user to
|
||||
* @param user The user to be added to the hub.
|
||||
*/
|
||||
extern void user_manager_add(struct user* user);
|
||||
extern int uman_add(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Remove a user from the user manager.
|
||||
* This user is connected, and will be moved to the leaving queue, pending
|
||||
* all messages in the message queue, and resource cleanup.
|
||||
*
|
||||
* @return 0 if successfully removed, -1 if error.
|
||||
*/
|
||||
extern void user_manager_remove(struct user* user);
|
||||
extern int uman_remove(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Returns a free sid for a new user.
|
||||
* Returns and allocates an unused session ID (SID).
|
||||
*/
|
||||
extern sid_t user_manager_get_free_sid(struct hub_info* hub);
|
||||
extern sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Lookup a user based on the session ID (sid).
|
||||
* NOTE: This will only search connected users.
|
||||
* Lookup a user based on the session ID (SID).
|
||||
*
|
||||
* NOTE: This function will only search connected users, which means
|
||||
* that SIDs assigned to users who are not yet completely logged in,
|
||||
* or are in the process of being disconnected will result in this
|
||||
* function returning NULL even though the sid is not freely available.
|
||||
*
|
||||
* FIXME: Is that really safe / sensible ?
|
||||
* - Makes sense from a message routing point of view.
|
||||
*
|
||||
* @return a user if found, or NULL if not found
|
||||
*/
|
||||
extern struct user* get_user_by_sid(struct hub_info* hub, sid_t sid);
|
||||
extern struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid);
|
||||
|
||||
/**
|
||||
* Lookup a user based on the client ID (cid).
|
||||
* Lookup a user based on the client ID (CID).
|
||||
* @return a user if found, or NULL if not found
|
||||
*/
|
||||
extern struct user* get_user_by_cid(struct hub_info* hub, const char* cid);
|
||||
extern struct hub_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 user* get_user_by_nick(struct hub_info* hub, const char* nick);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Send the user list of connected clients to 'user'.
|
||||
@@ -90,13 +112,13 @@ extern struct user* get_user_by_nick(struct hub_info* hub, const char* nick);
|
||||
*
|
||||
* @return 1 if sending the user list succeeded, 0 otherwise.
|
||||
*/
|
||||
extern int send_user_list(struct user* user);
|
||||
extern int uman_send_user_list(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
/**
|
||||
* Send a quit message to all connected users when 'user' is
|
||||
* leaving the hub (for whatever reason).
|
||||
*/
|
||||
extern void send_quit_message(struct user* user);
|
||||
extern void uman_send_quit_message(struct hub_info* hub, struct hub_user* user);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_USER_MANAGER_H */
|
||||
122
src/hubevent.c
122
src/hubevent.c
@@ -1,122 +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 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 user* u)
|
||||
{
|
||||
struct timeval timeout = { TIMEOUT_IDLE, 0 };
|
||||
|
||||
/* Send user list of all existing users */
|
||||
if (!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);
|
||||
user_manager_add(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(u);
|
||||
|
||||
/* reset to idle timeout */
|
||||
if (u->ev_read)
|
||||
event_add(u->ev_read, &timeout);
|
||||
}
|
||||
|
||||
void on_login_failure(struct user* u, enum status_message msg)
|
||||
{
|
||||
log_user_login_error(u, msg);
|
||||
hub_send_status(u, msg, status_level_fatal);
|
||||
user_disconnect(u, quit_logon_error);
|
||||
}
|
||||
|
||||
void on_nick_change(struct user* u, const char* nick)
|
||||
{
|
||||
if (user_is_logged_in(u))
|
||||
{
|
||||
log_user_nick_change(u, nick);
|
||||
}
|
||||
}
|
||||
|
||||
void on_logout_user(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 (user->hub->status == hub_status_shutdown)
|
||||
reason = "hub shutdown";
|
||||
else
|
||||
reason = "unknown error";
|
||||
break;
|
||||
}
|
||||
|
||||
log_user_logout(user, reason);
|
||||
user->quit_reason = 0;
|
||||
}
|
||||
|
||||
333
src/netevent.c
333
src/netevent.c
@@ -1,333 +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"
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
hub_send_ping(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)
|
||||
{
|
||||
if (hub_handle_message(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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ADC_UDP_OPERATION
|
||||
extern void net_on_packet(int fd, short ev, void *arg)
|
||||
{
|
||||
static char buffer[1024] = {0,};
|
||||
// struct hub_info* hub = (struct hub_info*) arg;
|
||||
// struct user* user = 0;
|
||||
ssize_t size;
|
||||
struct sockaddr_storage from;
|
||||
socklen_t fromlen;
|
||||
|
||||
size = recvfrom(fd, buffer, 1024, 0, (struct sockaddr*) &from, &fromlen);
|
||||
|
||||
// FIXME: A plugin should handle this!
|
||||
hub_log(log_info, "Datagram [%s] (%d bytes)", buffer, (int) size);
|
||||
}
|
||||
#endif
|
||||
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
|
||||
|
||||
@@ -1,290 +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 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 */
|
||||
|
||||
|
||||
|
||||
52
src/network/connection.c
Normal file
52
src/network/connection.c
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
41
src/network/connection.h
Normal file
41
src/network/connection.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
@@ -40,16 +40,19 @@ int net_initialize()
|
||||
struct WSAData wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
|
||||
{
|
||||
hub_log(log_error, "Unable to initialize winsock.");
|
||||
LOG_ERROR("Unable to initialize winsock.");
|
||||
return -1;
|
||||
}
|
||||
#endif /* WINSOCK */
|
||||
|
||||
hub_log(log_trace, "Initializing network monitor.");
|
||||
LOG_TRACE("Initializing network monitor.");
|
||||
net_stats_initialize();
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
/* FIXME: Initialize OpenSSL here. */
|
||||
LOG_TRACE("Initializing OpenSSL...");
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif /* SSL_SUPPORT */
|
||||
|
||||
net_initialized = 1;
|
||||
@@ -58,12 +61,27 @@ 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_shutdown()
|
||||
|
||||
int net_destroy()
|
||||
{
|
||||
if (net_initialized)
|
||||
{
|
||||
hub_log(log_trace, "Shutting down network monitor");
|
||||
LOG_TRACE("Shutting down network monitor");
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
/* FIXME: Shutdown OpenSSL here. */
|
||||
@@ -78,6 +96,11 @@ int net_shutdown()
|
||||
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()
|
||||
{
|
||||
@@ -103,22 +126,42 @@ 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
|
||||
return setsockopt(fd, level, opt, (const char*) optval, optlen);
|
||||
ret = setsockopt(fd, level, opt, (const char*) optval, optlen);
|
||||
#else
|
||||
return setsockopt(fd, level, opt, optval, optlen);
|
||||
ret = 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;
|
||||
|
||||
#ifdef NETAPI_DUMP
|
||||
hub_log(log_dump, "net_set_nonblocking(): fd=%d", fd);
|
||||
#endif
|
||||
|
||||
int ret = -1;
|
||||
#ifdef WINSOCK
|
||||
u_long on = toggle ? 1 : 0;
|
||||
ret = ioctlsocket(fd, FIONBIO, &on);
|
||||
@@ -127,36 +170,27 @@ int net_set_nonblocking(int fd, int toggle)
|
||||
#endif
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_set_nonblocking(): ioctl failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
net_error_out(fd, "net_set_nonblocking");
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
net_error_out(fd, "net_set_nosigpipe");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -164,54 +198,63 @@ 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)
|
||||
{
|
||||
hub_log(log_error, "net_set_linger(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
net_error_out(fd, "net_set_linger");
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
hub_log(log_error, "net_set_keepalive(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
net_error_out(fd, "net_set_keepalive");
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
hub_log(log_error, "net_set_reuseaddress(): setsockopt failed (fd=%d): %s", fd, net_error_string(net_error()));
|
||||
return -1;
|
||||
net_error_out(fd, "net_set_reuseaddress");
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -235,6 +278,32 @@ 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)
|
||||
{
|
||||
@@ -268,7 +337,7 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr)
|
||||
case EWOULDBLOCK:
|
||||
break;
|
||||
default:
|
||||
hub_log(log_error, "net_accept(): accept failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_error_out(fd, "net_accept");
|
||||
net_stats_add_error();
|
||||
return -1;
|
||||
}
|
||||
@@ -283,7 +352,18 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr)
|
||||
ipaddr->af = addr4->sin_family;
|
||||
if (ipaddr->af == AF_INET6)
|
||||
{
|
||||
memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
|
||||
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));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -303,7 +383,7 @@ int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
|
||||
{
|
||||
if (net_error() != EINPROGRESS)
|
||||
{
|
||||
hub_log(log_error, "net_connect(): connect failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_error_out(fd, "net_connect");
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
@@ -325,13 +405,12 @@ int net_is_ipv6_supported()
|
||||
if (net_error() == EAFNOSUPPORT)
|
||||
#endif
|
||||
{
|
||||
hub_log(log_trace, "net_is_ipv6_supported(): IPv6 is not supported on this system.");
|
||||
LOG_TRACE("net_is_ipv6_supported(): IPv6 is not supported on this system.");
|
||||
is_ipv6_supported = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub_log(log_error, "net_is_ipv6_supported(): Unknown error (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
|
||||
|
||||
net_error_out(ret, "net_is_ipv6_supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -339,7 +418,7 @@ int net_is_ipv6_supported()
|
||||
int off = 0;
|
||||
if (net_setsockopt(ret, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
|
||||
LOG_ERROR("net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
|
||||
is_ipv6_supported = 0;
|
||||
}
|
||||
else
|
||||
@@ -361,7 +440,7 @@ int net_socket_create(int af, int type, int protocol)
|
||||
int sd = socket(af, type, protocol);
|
||||
if (sd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): socket failed (errno=%d, msg=%s)", net_error(), net_error_string(net_error()));
|
||||
net_error_out(sd, "net_socket_create");
|
||||
}
|
||||
|
||||
#ifdef SOCK_DUAL_STACK_OPT
|
||||
@@ -371,7 +450,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)
|
||||
{
|
||||
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()));
|
||||
LOG_ERROR("net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -495,19 +574,18 @@ 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
|
||||
{
|
||||
hub_log(log_error, "net_get_peer_address(): getsockname failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_error_out(fd, "net_get_peer_address");
|
||||
net_stats_add_error();
|
||||
}
|
||||
|
||||
return "0.0.0.0";
|
||||
@@ -525,7 +603,7 @@ ssize_t net_recv(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
hub_log(log_debug, "net_recv(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
/* net_error_out(fd, "net_recv"); */
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
@@ -533,7 +611,7 @@ ssize_t net_recv(int fd, void* buf, size_t len, int flags)
|
||||
}
|
||||
|
||||
|
||||
ssize_t net_send(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 ret = send(fd, buf, len, flags);
|
||||
if (ret >= 0)
|
||||
@@ -544,7 +622,7 @@ ssize_t net_send(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
hub_log(log_debug, "net_send(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
/* net_error_out(fd, "net_send"); */
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
@@ -557,7 +635,7 @@ int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
|
||||
int ret = bind(fd, my_addr, addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_bind(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_error_out(fd, "net_bind");
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
@@ -569,7 +647,7 @@ int net_listen(int fd, int backlog)
|
||||
int ret = listen(fd, backlog);
|
||||
if (ret == -1)
|
||||
{
|
||||
hub_log(log_error, "net_listen(): failed (fd=%d, errno=%d, msg=%s)", fd, net_error(), net_error_string(net_error()));
|
||||
net_error_out(fd, "net_listen");
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
@@ -585,14 +663,12 @@ 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;
|
||||
@@ -605,37 +681,31 @@ 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++;
|
||||
@@ -30,6 +30,17 @@ 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
|
||||
@@ -47,7 +58,7 @@ extern int net_initialize();
|
||||
*
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_shutdown();
|
||||
extern int net_destroy();
|
||||
|
||||
/**
|
||||
* @return the number of sockets currrently being monitored.
|
||||
@@ -76,11 +87,20 @@ 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
|
||||
@@ -151,6 +171,38 @@ 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.
|
||||
*/
|
||||
@@ -159,7 +211,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, void* buf, size_t len, int flags);
|
||||
extern ssize_t net_send(int fd, const void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* This tries to create a AF_INET6 socket.
|
||||
@@ -210,11 +262,6 @@ 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
|
||||
@@ -243,10 +290,8 @@ 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
|
||||
52
src/plugin.h
52
src/plugin.h
@@ -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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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
266
src/route.c
@@ -1,266 +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 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 = get_user_by_sid(u->hub, msg->target);
|
||||
if (target)
|
||||
{
|
||||
route_to_user(target, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
target = 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;
|
||||
}
|
||||
61
src/sid.c
61
src/sid.c
@@ -1,61 +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;
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ static int recv_client(struct ADC_client* client)
|
||||
|
||||
char* start = client->recvbuf;
|
||||
char* pos;
|
||||
char* lastPos;
|
||||
char* lastPos = 0;
|
||||
while ((pos = strchr(start, '\n')))
|
||||
{
|
||||
lastPos = pos;
|
||||
@@ -482,9 +482,16 @@ static int recv_client(struct ADC_client* client)
|
||||
start = &pos[1];
|
||||
}
|
||||
|
||||
client->r_offset = strlen(lastPos);
|
||||
memmove(client->recvbuf, lastPos, strlen(lastPos));
|
||||
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
@@ -944,7 +951,7 @@ int main(int argc, char** argv)
|
||||
net_string_to_address(AF_INET, cfg_host, &saddr.sin_addr);
|
||||
|
||||
runloop(cfg_clients);
|
||||
net_shutdown();
|
||||
net_destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
src/uhub.h
75
src/uhub.h
@@ -23,6 +23,26 @@
|
||||
/* 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
|
||||
@@ -63,8 +83,10 @@
|
||||
#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
|
||||
@@ -122,41 +144,46 @@
|
||||
#define TIGERSIZE 24
|
||||
|
||||
#define MAX_RECV_BUF 65535
|
||||
#define MAX_SEND_BUF 65535
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
#endif
|
||||
|
||||
#include "adcconst.h"
|
||||
#include "adc/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 "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"
|
||||
#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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
308
src/user.c
308
src/user.c
@@ -1,308 +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"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static int convert_support_fourcc(int fourcc)
|
||||
{
|
||||
switch (fourcc)
|
||||
{
|
||||
case FOURCC('B','A','S','0'): /* Obsolete */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,234 +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"
|
||||
|
||||
/*
|
||||
* This callback function is used to clear user objects from the userlist.
|
||||
* Should only be used in user_manager_shutdown().
|
||||
*/
|
||||
static void clear_user_list_callback(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
struct user* u = (struct user*) ptr;
|
||||
|
||||
/* Mark the user as already being disconnected.
|
||||
* This prevents the hub from trying to send
|
||||
* quit messages to other users.
|
||||
*/
|
||||
u->credentials = cred_none;
|
||||
user_destroy(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void user_manager_update_stats(struct hub_info* hub)
|
||||
{
|
||||
const int factor = TIMEOUT_STATS;
|
||||
struct net_statistics* total;
|
||||
struct net_statistics* intermediate;
|
||||
net_stats_get(&intermediate, &total);
|
||||
|
||||
hub->stats.net_tx = (intermediate->tx / factor);
|
||||
hub->stats.net_rx = (intermediate->rx / factor);
|
||||
hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
|
||||
hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
|
||||
hub->stats.net_tx_total = total->tx;
|
||||
hub->stats.net_rx_total = total->rx;
|
||||
|
||||
net_stats_reset();
|
||||
}
|
||||
|
||||
|
||||
void user_manager_print_stats(struct hub_info* hub)
|
||||
{
|
||||
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,
|
||||
(int) hub->stats.net_rx / 1024,
|
||||
(int) hub->stats.net_tx_peak / 1024,
|
||||
(int) hub->stats.net_rx_peak / 1024);
|
||||
}
|
||||
|
||||
static void timer_statistics(int fd, short ev, void *arg)
|
||||
{
|
||||
struct hub_info* hub = (struct hub_info*) arg;
|
||||
struct timeval timeout = { TIMEOUT_STATS, 0 };
|
||||
user_manager_update_stats(hub);
|
||||
evtimer_set(&hub->ev_timer, timer_statistics, hub);
|
||||
event_base_set(hub->evbase, &hub->ev_timer);
|
||||
evtimer_add(&hub->ev_timer, &timeout);
|
||||
}
|
||||
|
||||
|
||||
int user_manager_init(struct hub_info* hub)
|
||||
{
|
||||
struct user_manager* users = NULL;
|
||||
struct timeval timeout = { TIMEOUT_STATS, 0 };
|
||||
|
||||
users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
|
||||
|
||||
users->list = list_create();
|
||||
users->free_sid = 1;
|
||||
|
||||
if (!users->list)
|
||||
{
|
||||
list_destroy(users->list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hub->users = users;
|
||||
|
||||
evtimer_set(&hub->ev_timer, timer_statistics, hub);
|
||||
event_base_set(hub->evbase, &hub->ev_timer);
|
||||
evtimer_add(&hub->ev_timer, &timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void user_manager_shutdown(struct hub_info* hub)
|
||||
{
|
||||
struct user_manager* users = hub->users;
|
||||
event_del(&hub->ev_timer);
|
||||
|
||||
list_clear(users->list, &clear_user_list_callback);
|
||||
list_destroy(users->list);
|
||||
hub_free(hub->users);
|
||||
}
|
||||
|
||||
|
||||
void user_manager_add(struct user* user)
|
||||
{
|
||||
list_append(user->hub->users->list, user);
|
||||
user->hub->users->count++;
|
||||
user->hub->users->count_peak = MAX(user->hub->users->count, user->hub->users->count_peak);
|
||||
|
||||
user->hub->users->shared_size += user->limits.shared_size;
|
||||
user->hub->users->shared_files += user->limits.shared_files;
|
||||
}
|
||||
|
||||
void user_manager_remove(struct user* user)
|
||||
{
|
||||
list_remove(user->hub->users->list, user);
|
||||
user->hub->users->count--;
|
||||
|
||||
user->hub->users->shared_size -= user->limits.shared_size;
|
||||
user->hub->users->shared_files -= user->limits.shared_files;
|
||||
}
|
||||
|
||||
|
||||
struct user* get_user_by_sid(struct hub_info* hub, sid_t 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 user* get_user_by_cid(struct hub_info* hub, const char* cid)
|
||||
{
|
||||
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 user*) list_get_next(hub->users->list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct user* get_user_by_nick(struct hub_info* hub, const char* nick)
|
||||
{
|
||||
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 user*) list_get_next(hub->users->list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int send_user_list(struct user* target)
|
||||
{
|
||||
int ret = 1;
|
||||
user_flag_set(target, flag_user_list);
|
||||
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(target, user->info);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
user = (struct user*) list_get_next(user->hub->users->list);
|
||||
}
|
||||
|
||||
if (!target->send_queue_size)
|
||||
{
|
||||
user_flag_unset(target, flag_user_list);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void 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));
|
||||
|
||||
if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
|
||||
{
|
||||
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
|
||||
}
|
||||
|
||||
route_to_all(leaving->hub, command);
|
||||
adc_msg_free(command);
|
||||
}
|
||||
|
||||
|
||||
sid_t user_manager_get_free_sid(struct hub_info* hub)
|
||||
{
|
||||
#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++;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "uhub.h"
|
||||
|
||||
|
||||
int ip_is_valid_ipv4(const char* address)
|
||||
{
|
||||
int i = 0; /* address index */
|
||||
@@ -147,7 +146,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)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to convert socket address (ipv6)");
|
||||
LOG_ERROR("Unable to convert socket address (ipv6)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -163,7 +162,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)
|
||||
{
|
||||
hub_log(log_fatal, "Unable to convert socket address (ipv4)");
|
||||
LOG_ERROR("Unable to convert socket address (ipv4)");
|
||||
return 0;
|
||||
}
|
||||
memcpy(addr, &addr4, sockaddr_size);
|
||||
@@ -219,7 +218,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));
|
||||
hub_log(log_debug, "Created left mask: %s", r_str);
|
||||
LOG_DUMP("Created left mask: %s", r_str);
|
||||
hub_free(r_str);
|
||||
#endif
|
||||
|
||||
@@ -272,7 +271,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));
|
||||
hub_log(log_debug, "Created right mask: %s", r_str);
|
||||
LOG_DUMP("Created right mask: %s", r_str);
|
||||
hub_free(r_str);
|
||||
#endif
|
||||
|
||||
@@ -405,7 +404,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));
|
||||
hub_log(log_debug, "Comparing IPs '%s' AND '%s' => %d", a_str, b_str, ret);
|
||||
LOG_DUMP("Comparing IPs '%s' AND '%s' => %d", a_str, b_str, ret);
|
||||
hub_free(a_str);
|
||||
hub_free(b_str);
|
||||
#endif
|
||||
@@ -413,13 +412,80 @@ 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);
|
||||
}
|
||||
@@ -33,26 +33,57 @@ 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),
|
||||
@@ -66,7 +97,6 @@ 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);
|
||||
|
||||
@@ -33,6 +33,31 @@ 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.
|
||||
@@ -47,7 +47,7 @@ void internal_debug_print_leaks()
|
||||
size_t n = 0;
|
||||
size_t leak = 0;
|
||||
size_t count = 0;
|
||||
hub_log(log_memory, "--- exit (allocs: %d, size: %zu) ---", hub_alloc_count, hub_alloc_size);
|
||||
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++;
|
||||
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("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, "--- done (allocs: %d, size: %zu, peak: %d/%zu, oom: %zu) ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom);
|
||||
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)
|
||||
{
|
||||
hub_log(log_memory, "--- start ---");
|
||||
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);
|
||||
|
||||
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);
|
||||
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
|
||||
{
|
||||
hub_log(log_memory, "%s *** OOM for %d bytes", where, size);
|
||||
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;
|
||||
hub_log(log_memory, "free %p (bt: %p %p) {allocs: %d, size: %zu}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
|
||||
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();
|
||||
hub_log(log_memory, "free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
|
||||
LOG_MEMORY("free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif /* REALTIME_MALLOC_TRACKING */
|
||||
@@ -179,26 +179,26 @@ int file_read_lines(const char* file, void* data, file_line_handler_t handler)
|
||||
|
||||
memset(buf, 0, MAX_RECV_BUF);
|
||||
|
||||
hub_log(log_trace, "Opening file %s for line reading.", file);
|
||||
LOG_TRACE("Opening file %s for line reading.", file);
|
||||
|
||||
fd = open(file, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
hub_log(log_error, "Unable to open file %s: %s", file, strerror(errno));
|
||||
LOG_ERROR("Unable to open file %s: %s", file, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = read(fd, buf, MAX_RECV_BUF);
|
||||
if (ret < 0)
|
||||
{
|
||||
hub_log(log_error, "Unable to read from file %s: %s", file, strerror(errno));
|
||||
LOG_ERROR("Unable to read from file %s: %s", file, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
close(fd);
|
||||
hub_log(log_warning, "File is empty.");
|
||||
LOG_WARN("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)
|
||||
{
|
||||
hub_log(log_dump, "Line: %s", start);
|
||||
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;
|
||||
hub_log(log_dump, "Line: %s", start);
|
||||
LOG_DUMP("Line: %s", start);
|
||||
if (handler(start, line_count+1, data) < 0)
|
||||
return -1;
|
||||
}
|
||||
@@ -319,4 +319,52 @@ 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;
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
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);
|
||||
@@ -34,7 +36,6 @@ 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);
|
||||
|
||||
@@ -53,6 +54,13 @@ 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 */
|
||||
|
||||
137
src/util/rbtree.c
Normal file
137
src/util/rbtree.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "rbtree.h"
|
||||
|
||||
#define RED 0
|
||||
#define BLACK 1
|
||||
|
||||
struct rb_node
|
||||
{
|
||||
const void* key;
|
||||
const void* value; /* data */
|
||||
int color;
|
||||
struct rb_node* parent;
|
||||
struct rb_node* left;
|
||||
struct rb_node* right;
|
||||
};
|
||||
|
||||
struct rb_tree
|
||||
{
|
||||
struct rb_node* root;
|
||||
size_t elements;
|
||||
rb_tree_alloc alloc;
|
||||
rb_tree_free free;
|
||||
rb_tree_compare compare;
|
||||
};
|
||||
|
||||
/* returns the grandparent of a node, if it exits */
|
||||
static inline struct rb_node* get_grandparent(struct rb_node* n)
|
||||
{
|
||||
if (n->parent)
|
||||
return n->parent->parent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rb_node* get_uncle(struct rb_node* n)
|
||||
{
|
||||
struct rb_node* gparent = n->parent ? n->parent->parent : 0;
|
||||
if (gparent)
|
||||
return (n->parent == gparent->left) ? gparent->right : gparent->left;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rb_node* tree_search(struct rb_tree* tree, const void* key)
|
||||
{
|
||||
struct rb_node* node = tree->root;
|
||||
while (node)
|
||||
{
|
||||
int res = tree->compare(key, node->key);
|
||||
if (res < 0) node = node->left;
|
||||
else if (res > 0) node = node->right;
|
||||
else return node;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rb_node* tree_insert(struct rb_tree* tree, const void* key, const void* value)
|
||||
{
|
||||
struct rb_node* node = tree->root;
|
||||
struct rb_node* newnode = tree->alloc(sizeof(struct rb_node));
|
||||
newnode->key = key;
|
||||
newnode->value = value;
|
||||
newnode->color = RED;
|
||||
|
||||
|
||||
while (node)
|
||||
{
|
||||
int res = tree->compare(key, node->key);
|
||||
if (res < 0) node = node->left;
|
||||
else if (res > 0) node = node->right;
|
||||
else
|
||||
{
|
||||
/* key already exists in tree */
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
||||
struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree_free f)
|
||||
{
|
||||
struct rb_tree* tree = a(sizeof(struct rb_tree));
|
||||
tree->compare = compare;
|
||||
tree->alloc = a;
|
||||
tree->free = f;
|
||||
return tree;
|
||||
}
|
||||
|
||||
void rb_tree_destroy(struct rb_tree* tree)
|
||||
{
|
||||
rb_tree_free f = tree->free;
|
||||
f(tree);
|
||||
}
|
||||
|
||||
void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* value)
|
||||
{
|
||||
struct rb_node* node = tree_insert(tree, key, value);
|
||||
if (node)
|
||||
return (void*) node->value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* rb_tree_remove(struct rb_tree* tree, const void* key)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void* rb_tree_get(struct rb_tree* tree, const void* key)
|
||||
{
|
||||
struct rb_node* node = tree_search(tree, key);
|
||||
if (node)
|
||||
return node->value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
38
src/util/rbtree.h
Normal file
38
src/util/rbtree.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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_RED_BLACK_TREE_H
|
||||
#define HAVE_UHUB_RED_BLACK_TREE_H
|
||||
|
||||
struct rb_tree;
|
||||
typedef int (*rb_tree_compare)(const void* a, const void* b);
|
||||
typedef void* (*rb_tree_alloc)(size_t);
|
||||
typedef void (*rb_tree_free)(void*);
|
||||
|
||||
|
||||
extern struct rb_tree* rb_tree_create(rb_tree_compare, rb_tree_alloc, rb_tree_free);
|
||||
extern void rb_tree_destroy(struct rb_tree*);
|
||||
|
||||
extern void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* data);
|
||||
extern void* rb_tree_remove(struct rb_tree* tree, const void* key);
|
||||
extern void* rb_tree_get(struct rb_tree* tree, const void* key);
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_RED_BLACK_TREE_H */
|
||||
|
||||
48
tools/adc-redirector
Executable file
48
tools/adc-redirector
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/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;
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
#define PRODUCT "uHub"
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT_TITLE
|
||||
#define PRODUCT_TITLE "(micro-Hub)"
|
||||
#ifndef GIT_REVISION
|
||||
#define REVISION ""
|
||||
#else
|
||||
#define REVISION " (git: " GIT_REVISION ")"
|
||||
#endif
|
||||
|
||||
#ifndef VERSION
|
||||
#define VERSION "0.2.8"
|
||||
#define VERSION "0.3.0-rc4" REVISION
|
||||
#endif
|
||||
|
||||
#ifndef COPYRIGHT
|
||||
|
||||
Reference in New Issue
Block a user