Compare commits

..

96 Commits

Author SHA1 Message Date
Jan Vidar Krey
f84f3b1fff Merge branch 'master' of github.com:janvidar/uhub into sans_libevent 2010-01-19 19:35:20 +01:00
Jan Vidar Krey
f84073f7cc Various fixes for epoll handling without libevent.
This should take care of most compile issues as well as busy loops caused by unhandled recv() calls returning 0 and general cleanups.
2010-01-19 17:52:58 +01:00
Jan Vidar Krey
af8421fa47 Crash fix. 2010-01-18 21:57:51 +01:00
Jan Vidar Krey
001fa6739a Crash fix. 2010-01-18 19:38:07 +01:00
Jan Vidar Krey
7dfa3162cb Epoll fixes. 2010-01-18 19:34:18 +01:00
Jan Vidar Krey
314707f499 Epoll fixes. 2010-01-18 16:15:38 +01:00
Jan Vidar Krey
1c58a85de1 More work on epoll. 2010-01-17 23:00:28 +01:00
lv77
eb5d3936a9 Add TODO file. Some modify example uhub.conf 2010-01-14 09:49:03 +03:00
lv77
23daa42b72 Add TODO file. Some modify example uhub.conf 2010-01-14 09:46:55 +03:00
root
a643bb123d Add init.d files for RedHat\CentOS 2010-01-13 16:27:07 +03:00
Jan Vidar Krey
6a4b9c58f4 Work on removing libevent completely as a mandatory dependency. 2010-01-07 20:55:13 +01:00
Jan Vidar Krey
f35b2c35cb Fix some compile errors. 2009-12-14 16:17:59 +01:00
Jan Vidar Krey
b3aa5332c8 Work on epoll backend, and removing dependency on libevent. 2009-12-10 23:12:04 +01:00
Jan Vidar Krey
1f9cfe58c4 No need to allow users not yet logged in to send special hub commands to the hub.
Nothing bad will happen, except the hub will try to answer them even though the user is not yet fully logged in. This fix ensures that these messages are simply dropped instead.
2009-12-09 19:40:12 +01:00
Jan Vidar Krey
50f5ce9d32 Fix bug #100 - Null pointer crash if sending a chat message without the message part. 2009-12-09 19:30:08 +01:00
Jan Vidar Krey
4a4de0f2ac Make sure we have libevent enabled for now, and add macro protection around the areas of the code that still depend on libevent. 2009-12-09 17:27:46 +01:00
Jan Vidar Krey
2e2f93d0a4 Started working on new timeout handling which can be used when we remove libevent.
This will probably be used by default on UNIX platforms at some point.

The timeout handling accomplishes O(1) inserts, removes and reschedules
but the accuracy is limited to whole seconds.
2009-12-09 17:12:33 +01:00
Jan Vidar Krey
7c093dc5da Fix for very long messages that get dropped if they are sent alone (no other message before it) and does not fit inside one TCP packet.
(Thanks FleetCommand!)
2009-12-04 08:12:54 +01:00
Jan Vidar Krey
8bcdbdc061 Removed assert. 2009-11-21 11:52:25 +01:00
Jan Vidar Krey
53536f191d Crash fix. 2009-11-21 11:47:26 +01:00
Jan Vidar Krey
e994f23ea0 Crash fix part 2 2009-11-18 18:35:31 +01:00
Jan Vidar Krey
f489e77602 Crash fix? 2009-11-18 18:27:31 +01:00
Jan Vidar Krey
2526c8a9ed Silly compile error. 2009-11-18 17:43:11 +01:00
Jan Vidar Krey
4556623a87 Clarify flags as unsigned. 2009-11-18 17:41:22 +01:00
Jan Vidar Krey
828c19cfc6 Fix a wrong open() if no motd is specified. 2009-11-18 17:41:55 +01:00
Jan Vidar Krey
00995a1946 Fix potential memory leaks and crashes. 2009-11-18 17:41:28 +01:00
Jan Vidar Krey
f4e82ef503 Cleanup the net_event handler. 2009-11-18 17:40:28 +01:00
Jan Vidar Krey
eb7bec585e Fix problems with write events not being processed due to a read event taking presendence.
Conflicts:

	src/core/netevent.c
2009-11-18 17:40:23 +01:00
Jan Vidar Krey
066b3f5243 Fix protocol probe. Will detect ADC and TLS handshake - any other request
will simply cause the hub to close the connection.

Conflicts:

	src/core/netevent.c
	src/core/probe.c
2009-11-18 17:38:25 +01:00
Jan Vidar Krey
a51e8830ce Log dropped messages. 2009-10-30 18:31:27 +01:00
Jan Vidar Krey
e6cc47070c A few minor TLS fixes 2009-10-09 21:38:14 +02:00
Jan Vidar Krey
0c5d98c671 TLS compile and crash fixes. 2009-10-09 21:11:11 +02:00
Jan Vidar Krey
0f30ebf045 Some stability fixes. Removed log messages. 2009-10-09 20:35:04 +02:00
Jan Vidar Krey
4919c8f2f9 Fix compile error. 2009-10-09 00:11:09 +02:00
Jan Vidar Krey
2910c571b0 Fix protocol probe. Will detect ADC and TLS handshake - any other request
will simply cause the hub to close the connection.
Fix problems with write events not being processed due to a read event taking presendence.
Fix bug #86: Windows does not have "getrlimit()".
2009-10-08 23:16:15 +02:00
Jan Vidar Krey
11e5683a79 Cleanup code somewhat. 2009-10-06 18:33:06 +02:00
Jan Vidar Krey
17416def35 Make sure we flag JOIN/LEAVE messages as really verbose debug output. 2009-10-06 18:28:16 +02:00
Jan Vidar Krey
234f04f495 Removed extra main block. 2009-10-06 18:25:50 +02:00
Jan Vidar Krey
4898454c91 Removed redundant and ununsed operation mode for adcrush. 2009-10-06 18:24:21 +02:00
Jan Vidar Krey
255255ff20 Allow for command line specified host. 2009-10-06 18:16:38 +02:00
Jan Vidar Krey
f50b40fb92 Fix bug #85 - Do not broadcast unknown commands, but allow for commands to be broadcasted if they are double escaped with ++ or !!. 2009-10-06 18:02:37 +02:00
Jan Vidar Krey
40fc09a7ef Whitespace cleanups. 2009-10-06 17:40:09 +02:00
Jan Vidar Krey
582bb58ff9 Refactor the address parsing bits of adcrush. 2009-10-06 17:25:38 +02:00
Jan Vidar Krey
7472e9ae4a Removed some old unused macros. 2009-10-06 15:53:24 +02:00
Jan Vidar Krey
f076c67c33 Added a configurable listen() backlog (defaults to: server_listen_backlog=50) 2009-10-06 15:50:42 +02:00
Jan Vidar Krey
7eef032584 Doc update. 2009-10-06 14:39:47 +02:00
Jan Vidar Krey
de793ea9d2 Some compile fixes and memory leak fixes for ADCRush. 2009-10-06 14:36:49 +02:00
Jan Vidar Krey
20ef6f8e53 Fix to net_con_close() which allows us to either delete the connection immediately if that is safe, or delete it later. 2009-10-06 14:36:05 +02:00
Jan Vidar Krey
310ddf4e9d More work on the ADC client lib. 2009-10-06 12:39:31 +02:00
Jan Vidar Krey
8592aa80d4 Compile fix. 2009-10-06 12:24:44 +02:00
Jan Vidar Krey
c3ba8d52ee Merge branch 'master' of baracus-vpn:~/git/uhub
Conflicts:
	src/adc/message.c
2009-10-06 12:18:14 +02:00
Jan Vidar Krey
69f6d811bf Added lots of asserts, and split out the ip address from the connection object.
Still a lot of work remains and a massive network connection cleanup is needed.
2009-09-29 00:30:52 +02:00
Jan Vidar Krey
a53c219f05 Fix bug #82 - Crash writing a log larger than 2GB on a 32 bit system as _FILE_OFFSET_BITS was not declared to be 64. 2009-09-14 12:24:18 +02:00
Jan Vidar Krey
96ce64ee07 Fix memory issues in ADC client lib. 2009-09-04 17:18:52 +02:00
Jan Vidar Krey
a3d6646b99 Fix a failing autotest. 2009-08-31 20:37:47 +02:00
Jan Vidar Krey
4fd182c55e Fix compile warning. 2009-08-31 20:36:25 +02:00
Jan Vidar Krey
993d9ae33b Fix some issues regarding header extraction. 2009-08-31 19:45:47 +02:00
Jan Vidar Krey
fe9b48f14c Added new convenient adc_msg_* functions for accessing named parameters. 2009-08-31 19:42:34 +02:00
Jan Vidar Krey
1e380ecf0f Fix bug #77 - Error in ACL command parsing. 2009-08-31 19:39:09 +02:00
Jan Vidar Krey
af7b52b708 Cleanup argument extraction. 2009-08-31 12:25:06 +02:00
Jan Vidar Krey
aeba7188c0 Added a macro that can keep the line count down. 2009-08-28 18:10:41 +02:00
Jan Vidar Krey
4ca5caa52b Various fixes, the admin tool at least compiles and runs. 2009-08-28 18:05:58 +02:00
Jan Vidar Krey
5203ecdadc Split uhub.h 2009-08-28 16:18:18 +02:00
Jan Vidar Krey
11b288a669 Various build fixes. 2009-08-28 16:04:45 +02:00
Jan Vidar Krey
52cbec24b6 Started splitting up ADC rush. Need a test client before we can proceed anyway. 2009-08-28 14:29:19 +02:00
Jan Vidar Krey
29d6d59d36 Misc connection changes. 2009-08-27 14:15:18 +02:00
Jan Vidar Krey
96c006ee13 Cleanup some code. 2009-08-23 14:36:52 +02:00
Jan Vidar Krey
e67587b997 Fix output handling. 2009-08-23 14:36:17 +02:00
Jan Vidar Krey
1af613d9ce Fixed printf issues with size_t. Since Windows do not support %zu we have to use %Iu there instead.
Solved that with an ugly but needed macro.
2009-08-20 10:44:44 +02:00
Jan Vidar Krey
5bd258ca52 Move the network related flags from network.h to connection.h since that is where they are used. 2009-08-11 21:29:51 +02:00
Jan Vidar Krey
86ba3ca86f Complete moving all connection related data out of the hub_user object. 2009-08-07 00:22:30 +02:00
Jan Vidar Krey
cfb450c3fc Added net_set_nonblocking for Solaris. 2009-08-06 23:28:44 +02:00
Jan Vidar Krey
cd389742e6 Solaris fixes. 2009-08-06 23:15:55 +02:00
Jan Vidar Krey
4afa187f9a Expose SSL/TLS related config variables. 2009-08-06 23:05:53 +02:00
Jan Vidar Krey
b3c40f7443 Use -levent not -lev 2009-08-04 04:59:52 +02:00
Jan Vidar Krey
d45383fe4d Fix some asserts. 2009-08-04 04:58:55 +02:00
Jan Vidar Krey
1642b8dfbe Use new connection data structs. 2009-08-04 04:47:31 +02:00
Jan Vidar Krey
ffd455474a Fix use of wrong event types. 2009-08-04 04:47:02 +02:00
Jan Vidar Krey
5baf277f5a Various fixes. 2009-08-04 04:46:24 +02:00
Jan Vidar Krey
ab6eda2bbb Disabled SID allocation debug messages by default. 2009-08-04 03:38:12 +02:00
Jan Vidar Krey
c17ae06b93 Added some memory debugging facilities to the adc_message structures. 2009-08-04 03:37:30 +02:00
Jan Vidar Krey
faaa3d14e4 Dont clear the timer, instead set the TIMEOUT_IDLE when logging in (for now at least) 2009-08-04 01:07:12 +02:00
Jan Vidar Krey
9f784e808e Fix bug #70 - crash if client is in nat_ip zone, but does not provide an IP in the INF message. 2009-08-04 01:02:49 +02:00
Jan Vidar Krey
b9adaa4f8b Fix libevent init. 2009-08-04 00:22:08 +02:00
Jan Vidar Krey
80dee0c020 Get rid of the event_base_set() calls. 2009-08-04 00:15:04 +02:00
Jan Vidar Krey
604c2d8836 Disable SSL by default. 2009-08-03 23:59:19 +02:00
Jan Vidar Krey
eca0f931bd Fixes to shutdown... 2009-08-03 23:59:02 +02:00
Jan Vidar Krey
fbe98d6011 Move the timeout handling to the connection object. 2009-08-03 21:57:18 +02:00
Jan Vidar Krey
4a5993ccc2 Added a generic SSL handshake mechanism. 2009-08-03 20:21:59 +02:00
Jan Vidar Krey
a297c08bba Dont use DEBUG messages, instead a much lower level messages for SSL related debug messages. 2009-08-03 19:55:57 +02:00
Jan Vidar Krey
7229ad68ab Make sure we send with the same arguments again if SSL_write() fails with SSL_ERROR_WANT_READ. 2009-08-03 19:54:28 +02:00
Jan Vidar Krey
22f9be95d0 ensure we close the SSL connection if we get SSL_ERROR_ZERO_RETURN. 2009-08-03 18:20:08 +02:00
Jan Vidar Krey
4e43746c1b Moved the ipaddr object into the connection object. 2009-08-03 18:14:34 +02:00
Jan Vidar Krey
27c71a75ee Hook in the new connection work, also implemented some missing bits
and pieces of SSL.
SSL seems to work at some basic level, and is largely untested.
2009-08-03 17:25:52 +02:00
Jan Vidar Krey
1d363ed0b4 Expose the SSL_connect() and SSL_accept() functions. 2009-08-03 14:21:53 +02:00
Jan Vidar Krey
79cf5ee9db Some work on integrating OpenSSL. 2009-08-03 03:55:38 +02:00
55 changed files with 3273 additions and 1406 deletions

8
.gitignore vendored
View File

@@ -1,2 +1,8 @@
*~ *~
*.o *.[oa]
*.exe
*.gch
uhub-admin
adcrush
uhub

View File

@@ -1,6 +1,6 @@
## ##
## Makefile for uhub (Use GNU make) ## Makefile for uhub (Use GNU make)
## Copyright (C) 2007-2009, Jan Vidar Krey <janvidar@extatic.org> ## Copyright (C) 2007-2010, Jan Vidar Krey <janvidar@extatic.org>
# #
CC = gcc CC = gcc
@@ -8,12 +8,11 @@ LD := $(CC)
MV := mv MV := mv
RANLIB := ranlib RANLIB := ranlib
CFLAGS += -pipe -Wall CFLAGS += -pipe -Wall
USE_PCH ?= YES
USE_SSL ?= NO USE_SSL ?= NO
USE_LIBEVENT ?= NO
USE_BIGENDIAN ?= AUTO USE_BIGENDIAN ?= AUTO
BITS ?= AUTO BITS ?= AUTO
SILENT ?= YES SILENT ?= YES
LDLIBS += -levent
TERSE ?= NO TERSE ?= NO
STACK_PROTECT ?= NO STACK_PROTECT ?= NO
@@ -21,6 +20,9 @@ ifeq ($(OS), Windows_NT)
WINDOWS ?= YES WINDOWS ?= YES
endif endif
ifeq (SOLARIS,YES)
LDLIBS += -lsocket -lnsl
endif
CFLAGS += -I./src/ CFLAGS += -I./src/
@@ -44,19 +46,16 @@ endif
ifeq ($(SILENT),YES) ifeq ($(SILENT),YES)
MSG_CC=@echo " CC:" $(notdir $^) && MSG_CC=@echo " CC:" $(notdir $^) &&
MSG_PCH=@echo " PCH:" $(notdir $@) &&
MSG_LD=@echo " LD:" $(notdir $@) && MSG_LD=@echo " LD:" $(notdir $@) &&
MSG_AR=@echo " AR:" $(notdir $@) && MSG_AR=@echo " AR:" $(notdir $@) &&
else else
MSG_CC= MSG_CC=
MSG_PCH=
MSG_LD= MSG_LD=
MSG_AR= MSG_AR=
endif endif
ifeq ($(TERSE), YES) ifeq ($(TERSE), YES)
MSG_CC=@ MSG_CC=@
MSG_PCH=@
MSG_LD=@ MSG_LD=@
MSG_AR=@ MSG_AR=@
MSG_CLEAN=-n "" MSG_CLEAN=-n ""
@@ -64,8 +63,8 @@ else
MSG_CLEAN="Clean as a whistle" MSG_CLEAN="Clean as a whistle"
endif endif
CFLAGS += -I/source/libevent # CFLAGS += -I/source/libevent
LDFLAGS += -L/source/libevent # LDFLAGS += -L/source/libevent
ifeq ($(RELEASE),YES) ifeq ($(RELEASE),YES)
CFLAGS += -O3 -DNDEBUG CFLAGS += -O3 -DNDEBUG
@@ -90,13 +89,6 @@ CFLAGS += -finstrument-functions
CFLAGS += -DDEBUG_FUNCTION_TRACE CFLAGS += -DDEBUG_FUNCTION_TRACE
endif endif
ifeq ($(USE_PCH),YES)
PCHSRC=src/uhub.h
PCH=src/uhub.h.gch
else
PCH=
endif
ifneq ($(BITS), AUTO) ifneq ($(BITS), AUTO)
ifeq ($(BITS), 64) ifeq ($(BITS), 64)
CFLAGS += -m64 CFLAGS += -m64
@@ -124,10 +116,14 @@ CFLAGS += -DSSL_SUPPORT
LDLIBS += -lssl LDLIBS += -lssl
endif endif
ifeq ($(USE_LIBEVENT),YES)
CFLAGS += -DUSE_LIBEVENT
LDLIBS += -levent
ifneq ($(LIBEVENT_PATH),) ifneq ($(LIBEVENT_PATH),)
CFLAGS += -I$(LIBEVENT_PATH) CFLAGS += -I$(LIBEVENT_PATH)
LDFLAGS += -L$(LIBEVENT_PATH) LDFLAGS += -L$(LIBEVENT_PATH)
endif endif
endif
ifeq ($(GIT_REVISION),YES) ifeq ($(GIT_REVISION),YES)
CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\" CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\"
@@ -143,54 +139,36 @@ libuhub_SOURCES := \
src/core/hubevent.c \ src/core/hubevent.c \
src/core/hubio.c \ src/core/hubio.c \
src/core/inf.c \ src/core/inf.c \
src/core/netevent.c \
src/core/probe.c \
src/core/route.c \
src/core/user.c \
src/core/usermanager.c \
src/network/connection.c \
src/network/epoll.c \
src/network/libevent.c \
src/network/network.c \
src/util/ipcalc.c \ src/util/ipcalc.c \
src/util/list.c \ src/util/list.c \
src/util/log.c \ src/util/log.c \
src/util/memory.c \ src/util/memory.c \
src/adc/message.c \
src/util/misc.c \ src/util/misc.c \
src/core/netevent.c \
src/network/connection.c \
src/network/network.c \
src/util/rbtree.c \ src/util/rbtree.c \
src/core/route.c \ src/util/timeout.c \
src/adc/sid.c \ src/util/tiger.c
src/util/tiger.c \
src/core/user.c \ libadc_common_SOURCES := \
src/core/usermanager.c src/adc/message.c \
src/adc/sid.c
libadc_client_SOURCES := \
src/tools/adcclient.c
uhub_SOURCES := src/core/main.c uhub_SOURCES := src/core/main.c
adcrush_SOURCES := src/tools/adcrush.c adcrush_SOURCES := src/tools/adcrush.c
admin_SOURCES := src/admin.c admin_SOURCES := src/tools/admin.c
uhub_HEADERS := \
src/adc/adcconst.h \
src/core/auth.h \
src/core/config.h \
src/core/eventid.h \
src/core/eventqueue.h \
src/core/hub.h \
src/core/hubevent.h \
src/core/hubio.h \
src/core/inf.h \
src/util/ipcalc.h \
src/util/list.h \
src/util/log.h \
src/util/memory.h \
src/adc/message.h \
src/util/misc.h \
src/core/netevent.h \
src/network/connection.h \
src/network/network.h \
src/util/rbtree.h \
src/core/route.h \
src/adc/sid.h \
src/util/tiger.h \
src/uhub.h \
src/core/user.h \
src/core/usermanager.h
autotest_SOURCES := \ autotest_SOURCES := \
autotest/test_message.tcc \ autotest/test_message.tcc \
@@ -207,14 +185,16 @@ autotest_SOURCES := \
autotest_OBJECTS = autotest.o autotest_OBJECTS = autotest.o
# Source to objects # Source to objects
libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o) libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o)
uhub_OBJECTS := $(uhub_SOURCES:.c=.o) libadc_client_OBJECTS := $(libadc_client_SOURCES:.c=.o)
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o) libadc_common_OBJECTS := $(libadc_common_SOURCES:.c=.o)
admin_OBJECTS := $(admin_SOURCES:.c=.o)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) uhub_OBJECTS := $(uhub_SOURCES:.c=.o)
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o)
admin_OBJECTS := $(admin_SOURCES:.c=.o)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
LIBUHUB=libuhub.a
uhub_BINARY=uhub$(BIN_EXT) uhub_BINARY=uhub$(BIN_EXT)
adcrush_BINARY=adcrush$(BIN_EXT) adcrush_BINARY=adcrush$(BIN_EXT)
admin_BINARY=uhub-admin$(BIN_EXT) admin_BINARY=uhub-admin$(BIN_EXT)
@@ -223,24 +203,16 @@ autotest_BINARY=autotest/test$(BIN_EXT)
%.o: %.c %.o: %.c
$(MSG_CC) $(CC) -c $(CFLAGS) -o $@ $^ $(MSG_CC) $(CC) -c $(CFLAGS) -o $@ $^
all: $(uhub_BINARY) $(PCH) all: $(uhub_BINARY)
$(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS) $(adcrush_BINARY): $(adcrush_OBJECTS) $(libuhub_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
$(admin_BINARY): $(PCH) $(LIBUHUB) $(admin_OBJECTS) $(admin_BINARY): $(admin_OBJECTS) $(libuhub_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
$(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS) $(uhub_BINARY): $(uhub_OBJECTS) $(libuhub_OBJECTS) $(libadc_common_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
$(LIBUHUB): $(libuhub_OBJECTS)
$(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@
ifeq ($(USE_PCH),YES)
$(PCH): $(uhub_HEADERS)
$(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC)
endif
autotest.c: $(autotest_SOURCES) autotest.c: $(autotest_SOURCES)
$(shell exotic --standalone $(autotest_SOURCES) > $@) $(shell exotic --standalone $(autotest_SOURCES) > $@)
@@ -248,7 +220,7 @@ autotest.c: $(autotest_SOURCES)
$(autotest_OBJECTS): autotest.c $(autotest_OBJECTS): autotest.c
$(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@ $< $(MSG_CC) $(CC) -c $(CFLAGS) -Isrc -o $@ $<
$(autotest_BINARY): $(autotest_OBJECTS) $(LIBUHUB) $(autotest_BINARY): $(autotest_OBJECTS) $(libuhub_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
autotest: $(autotest_BINARY) autotest: $(autotest_BINARY)
@@ -269,10 +241,10 @@ install: $(uhub_BINARY)
endif endif
dist-clean: dist-clean:
@rm -rf $(all_OBJECTS) $(PCH) *~ core @rm -rf $(all_OBJECTS) *~ core
clean: clean:
@rm -rf $(libuhub_OBJECTS) $(PCH) *~ core $(uhub_BINARY) $(LIBUHUB) $(all_OBJECTS) && \ @rm -rf $(libuhub_OBJECTS) *~ core $(uhub_BINARY) $(admin_BINARY) $(autotest_BINARY) $(adcrush_BINARY) $(all_OBJECTS) autotest.c && \
echo $(MSG_CLEAN) echo $(MSG_CLEAN)

0
TODO Normal file
View File

View File

@@ -42,8 +42,8 @@ static void inf_create_user()
{ {
if (inf_user) return; if (inf_user) return;
inf_user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user)); inf_user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
inf_user->connection = net_con_create();
inf_user->id.sid = 1; inf_user->id.sid = 1;
inf_user->net.connection.sd = -1;
inf_user->limits.upload_slots = 1; inf_user->limits.upload_slots = 1;
} }

View File

@@ -31,7 +31,9 @@ EXO_TEST(adc_message_parse_1, {
EXO_TEST(adc_message_parse_2, { EXO_TEST(adc_message_parse_2, {
struct adc_message* msg = adc_msg_create(test_string2); struct adc_message* msg = adc_msg_create(test_string2);
return msg == NULL; int ok = (msg != NULL);
adc_msg_free(msg);
return ok;
}); });
EXO_TEST(adc_message_parse_3, { EXO_TEST(adc_message_parse_3, {

View File

@@ -4,6 +4,7 @@
static struct hub_info um_hub; static struct hub_info um_hub;
static struct hub_user um_user[MAX_USERS]; static struct hub_user um_user[MAX_USERS];
// static struct net_connection um_cons[MAX_USERS];
EXO_TEST(um_test_setup, { EXO_TEST(um_test_setup, {
int i = 0; int i = 0;
@@ -11,9 +12,12 @@ EXO_TEST(um_test_setup, {
for (i = 0; i < MAX_USERS; i++) for (i = 0; i < MAX_USERS; i++)
{ {
/* memset(&um_cons[i], 0, sizeof(struct net_connection));
um_cons[i].sd = -1;
memset(&um_user[i], 0, sizeof(struct hub_user)); memset(&um_user[i], 0, sizeof(struct hub_user));
um_user[i].id.sid = i+1; um_user[i].id.sid = i+1;
um_user[i].net.connection.sd = -1; um_user[i].connection = &um_cons[i];*/
} }
return 1; return 1;
}); });

101
doc/init.d.RedHat/etc/init.d/uhub Executable file
View File

@@ -0,0 +1,101 @@
#!/bin/sh
#
# chkconfig: - 91 35
# description: Starts and stops the Uhub ( http://www.extatic.org/uhub ) daemons on RHEL\CentOS \
# used to provide p2p network services.
#
# pidfile: /var/run/uhub.pid
# config: /etc/uhub/uhub.conf
# Source function library.
if [ -f /etc/init.d/functions ] ; then
. /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ] ; then
. /etc/rc.d/init.d/functions
else
exit 1
fi
# Avoid using root's TMPDIR
unset TMPDIR
# Source networking configuration.
. /etc/sysconfig/network
if [ -f /etc/sysconfig/uhub ]; then
. /etc/sysconfig/uhub
fi
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 1
# Check that uhub.conf exists.
[ -f /etc/uhub/uhub.conf ] || exit 6
RETVAL=0
start() {
KIND="UHUB"
echo -n $"Starting $KIND services: "
daemon uhub $UHUBOPTIONS
RETVAL=$?
echo ""
return $RETVAL
}
stop() {
KIND="UHUB"
echo -n $"Shutting down $KIND services: "
killproc uhub
RETVAL=$?
echo ""
return $RETVAL
}
restart() {
stop
start
}
reload() {
echo -n $"Reloading uhub.conf / user.conf file: "
killproc uhub -HUP
RETVAL=$?
echo ""
return $RETVAL
}
rhstatus() {
status uhub
RETVAL=$?
if [ $RETVAL -ne 0 ] ; then
return $RETVAL
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
reload)
reload
;;
status)
rhstatus
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 2
esac
exit $?

View File

@@ -0,0 +1,15 @@
# Options to UHUB
# -v Verbose mode. Add more -v's for higher verbosity.
# -q Quiet mode - no output
# -f Fork to background
# -l <file> Log messages to given file (default: stderr)
# -L Log messages to syslog
# -c <file> Specify configuration file (default: /etc/uhub/uhub.conf)
# -S Show configuration parameters, but ignore defaults
# -u <user> Run as given user
# -g <group> Run with given group permissions
# -p <file> Store pid in file (process id)
UHUBOPTIONS=" -u uhub -f -p /var/run/uhub.pid -l /var/log/uhub.log"

View File

@@ -4,7 +4,8 @@
# #
# This file is read only to the uhub deamon, and if you # This file is read only to the uhub deamon, and if you
# make changes to it while uhub is running you can send a # make changes to it while uhub is running you can send a
# HUP signal to it, to reparse configuration (only on UNIX). # HUP signal to it ( $ killall -HUP uhub ), to reparse configuration (only on UNIX).
# All configuration directives: http://www.uhub.org/config.php
# Bind to this port and address # Bind to this port and address
# server_bind_addr=any means listen to "::" if IPv6 is supported # server_bind_addr=any means listen to "::" if IPv6 is supported
@@ -38,6 +39,23 @@ file_acl=/etc/uhub/users.conf
# Normally this message is sent to clients when connecting. # Normally this message is sent to clients when connecting.
file_motd=/etc/uhub/motd.txt file_motd=/etc/uhub/motd.txt
# Slots\share\hubs limits
limit_max_hubs_user = 0
limit_max_hubs_reg = 0
limit_max_hubs_op = 0
limit_max_hubs = 0
limit_min_hubs_user = 0
limit_min_hubs_reg = 0
limit_min_hubs_op = 0
limit_min_share = 0
# Example:
# To require users to share at least 1 GB in order to enter the hub:
# limit_min_share = 1024
limit_max_share = 0
limit_min_slots = 0
limit_max_slots = 0
# Configure status message as sent to clients in different circumstances. # Configure status message as sent to clients in different circumstances.
msg_hub_full = Hub is full msg_hub_full = Hub is full
msg_hub_disabled = Hub is disabled msg_hub_disabled = Hub is disabled
@@ -61,6 +79,12 @@ msg_ban_permanently = Banned permanently
msg_ban_temporarily = Banned temporarily msg_ban_temporarily = Banned temporarily
msg_auth_invalid_password = Password is wrong msg_auth_invalid_password = Password is wrong
msg_auth_user_not_found = User not found in password database msg_auth_user_not_found = User not found in password database
msg_user_share_size_low = User is not sharing enough
msg_user_share_size_high = User is sharing too much
msg_user_slots_low = User have too few upload slots
msg_user_slots_high = User have too many upload slots
msg_user_hub_limit_low = User is on too few hubs
msg_user_hub_limit_high = User is on too many hubs
msg_error_no_memory = No memory msg_error_no_memory = No memory

View File

@@ -26,17 +26,71 @@
uhub_assert(X->capacity); \ uhub_assert(X->capacity); \
uhub_assert(X->length); \ uhub_assert(X->length); \
uhub_assert(X->length <= X->capacity); \ uhub_assert(X->length <= X->capacity); \
uhub_assert(X->length == strlen(X->cache)); \ uhub_assert(X->length == strlen(X->cache));
uhub_assert(X->references >= 0);
#else #else
#define ADC_MSG_ASSERT(X) do { } while(0) #define ADC_MSG_ASSERT(X) do { } while(0)
#endif #endif /* DEBUG */
#ifdef MSG_MEMORY_DEBUG
#undef msg_malloc
#undef msg_malloc_zero
#undef msg_free
static void* msg_malloc(size_t size)
{
void* ptr = valloc(size);
LOG_MEMORY("msg_malloc: %p %d", ptr, (int) size);
return ptr;
}
static void* msg_malloc_zero(size_t size)
{
void* ptr = msg_malloc(size);
memset(ptr, 0, size);
return ptr;
}
static void msg_free(void* ptr)
{
LOG_MEMORY("msg_free: %p", ptr);
// hub_free(ptr);
}
#include <sys/mman.h>
static void adc_msg_protect(struct adc_message* cmd)
{
LOG_MEMORY("msg_prot: %p %d", cmd, cmd->capacity);
mprotect(cmd, sizeof(cmd), PROT_READ);
mprotect(cmd->cache, sizeof(cmd->capacity), PROT_READ);
}
static void adc_msg_unprotect(struct adc_message* cmd)
{
LOG_MEMORY("msg_unprot: %p %d", cmd, cmd->capacity);
mprotect(cmd, sizeof(cmd), PROT_READ | PROT_WRITE);
mprotect(cmd->cache, sizeof(cmd->capacity), PROT_READ | PROT_WRITE);
}
#else
#define msg_malloc(X) hub_malloc(X)
#define msg_malloc_zero(X) hub_malloc_zero(X)
#define msg_free(X) hub_free(X)
#endif /* MSG_MEMORY_DEBUG */
struct adc_message* adc_msg_incref(struct adc_message* msg) struct adc_message* adc_msg_incref(struct adc_message* msg)
{ {
if (!msg) return 0; if (!msg) return 0;
#ifndef ADC_MESSAGE_INCREF #ifndef ADC_MESSAGE_INCREF
#ifdef MSG_MEMORY_DEBUG
adc_msg_unprotect(msg);
#endif
msg->references++; msg->references++;
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(msg);
#endif
return msg; return msg;
#else #else
struct adc_message* copy = adc_msg_copy(msg); struct adc_message* copy = adc_msg_copy(msg);
@@ -56,24 +110,25 @@ static int adc_msg_grow(struct adc_message* msg, size_t size)
if (msg->capacity > size) if (msg->capacity > size)
return 1; return 1;
/* Make sure we align our data */ /* Make sure we align our data */
newsize = size; newsize = size;
newsize += 2; /* termination */ newsize += 2; /* termination */
newsize += (newsize % sizeof(size_t)); /* alignment padding */ newsize += (newsize % sizeof(size_t)); /* alignment padding */
buf = hub_malloc_zero(newsize); buf = msg_malloc_zero(newsize);
if (!buf) if (!buf)
return 0; return 0;
if (msg->cache) if (msg->cache)
{ {
memcpy(buf, msg->cache, msg->length); memcpy(buf, msg->cache, msg->length);
hub_free(msg->cache); msg_free(msg->cache);
} }
msg->cache = buf; msg->cache = buf;
msg->capacity = newsize; msg->capacity = newsize;
return 1; return 1;
} }
@@ -85,10 +140,10 @@ static int adc_msg_cache_append(struct adc_message* msg, const char* string, siz
/* FIXME: OOM! */ /* FIXME: OOM! */
return 0; return 0;
} }
memcpy(&msg->cache[msg->length], string, len); memcpy(&msg->cache[msg->length], string, len);
adc_msg_set_length(msg, msg->length + len); adc_msg_set_length(msg, msg->length + len);
assert(msg->capacity > msg->length); assert(msg->capacity > msg->length);
msg->cache[msg->length] = 0; msg->cache[msg->length] = 0;
return 1; return 1;
@@ -148,14 +203,23 @@ void adc_msg_free(struct adc_message* msg)
if (!msg) return; if (!msg) return;
ADC_MSG_ASSERT(msg); ADC_MSG_ASSERT(msg);
if (msg->references > 0) if (msg->references > 0)
{ {
#ifdef MSG_MEMORY_DEBUG
adc_msg_unprotect(msg);
#endif
msg->references--; msg->references--;
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(msg);
#endif
} }
else else
{ {
hub_free(msg->cache); #ifdef MSG_MEMORY_DEBUG
adc_msg_unprotect(msg);
#endif
msg_free(msg->cache);
if (msg->feature_cast_include) if (msg->feature_cast_include)
{ {
@@ -171,7 +235,7 @@ void adc_msg_free(struct adc_message* msg)
msg->feature_cast_exclude = 0; msg->feature_cast_exclude = 0;
} }
hub_free(msg); msg_free(msg);
} }
} }
@@ -179,11 +243,11 @@ void adc_msg_free(struct adc_message* msg)
struct adc_message* adc_msg_copy(const struct adc_message* cmd) struct adc_message* adc_msg_copy(const struct adc_message* cmd)
{ {
char* tmp = 0; char* tmp = 0;
struct adc_message* copy = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message)); struct adc_message* copy = (struct adc_message*) msg_malloc_zero(sizeof(struct adc_message));
if (!copy) return NULL; /* OOM */ if (!copy) return NULL; /* OOM */
ADC_MSG_ASSERT(cmd); ADC_MSG_ASSERT(cmd);
/* deep copy */ /* deep copy */
copy->cmd = cmd->cmd; copy->cmd = cmd->cmd;
copy->source = cmd->source; copy->source = cmd->source;
@@ -195,7 +259,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
copy->references = 0; copy->references = 0;
copy->feature_cast_include = 0; copy->feature_cast_include = 0;
copy->feature_cast_exclude = 0; copy->feature_cast_exclude = 0;
if (cmd->cache) if (cmd->cache)
{ {
if (!adc_msg_grow(copy, copy->length)) if (!adc_msg_grow(copy, copy->length))
@@ -206,7 +270,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
memcpy(copy->cache, cmd->cache, cmd->length); memcpy(copy->cache, cmd->cache, cmd->length);
copy->cache[copy->length] = 0; copy->cache[copy->length] = 0;
} }
if (cmd->feature_cast_include) if (cmd->feature_cast_include)
{ {
copy->feature_cast_include = list_create(); copy->feature_cast_include = list_create();
@@ -217,7 +281,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
tmp = list_get_next(cmd->feature_cast_include); tmp = list_get_next(cmd->feature_cast_include);
} }
} }
if (cmd->feature_cast_exclude) if (cmd->feature_cast_exclude)
{ {
copy->feature_cast_exclude = list_create(); copy->feature_cast_exclude = list_create();
@@ -228,9 +292,12 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
tmp = list_get_next(cmd->feature_cast_exclude); tmp = list_get_next(cmd->feature_cast_exclude);
} }
} }
ADC_MSG_ASSERT(copy); ADC_MSG_ASSERT(copy);
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(copy);
#endif
return copy; return copy;
} }
@@ -255,7 +322,7 @@ struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* line, s
struct adc_message* adc_msg_parse(const char* line, size_t length) struct adc_message* adc_msg_parse(const char* line, size_t length)
{ {
struct adc_message* command = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message)); struct adc_message* command = (struct adc_message*) msg_malloc_zero(sizeof(struct adc_message));
char prefix = line[0]; char prefix = line[0];
size_t n = 0; size_t n = 0;
char temp_sid[5]; char temp_sid[5];
@@ -269,7 +336,7 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
if (!is_printable_utf8(line, length)) if (!is_printable_utf8(line, length))
{ {
LOG_DEBUG("Dropped message with non-printable UTF-8 characters."); LOG_DEBUG("Dropped message with non-printable UTF-8 characters.");
hub_free(command); msg_free(command);
return NULL; return NULL;
} }
@@ -280,7 +347,7 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
if (!adc_msg_grow(command, length + need_terminate)) if (!adc_msg_grow(command, length + need_terminate))
{ {
hub_free(command); msg_free(command);
return NULL; /* OOM */ return NULL; /* OOM */
} }
@@ -352,8 +419,8 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
{ {
list_destroy(command->feature_cast_include); list_destroy(command->feature_cast_include);
list_destroy(command->feature_cast_exclude); list_destroy(command->feature_cast_exclude);
hub_free(command->cache); msg_free(command->cache);
hub_free(command); msg_free(command);
return NULL; /* OOM */ return NULL; /* OOM */
} }
@@ -443,20 +510,23 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
} }
ADC_MSG_ASSERT(command); ADC_MSG_ASSERT(command);
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(command);
#endif
return command; return command;
} }
struct adc_message* adc_msg_create(const char* line) struct adc_message* adc_msg_create(const char* line)
{ {
return adc_msg_parse_verify(NULL, line, strlen(line)); return adc_msg_parse(line, strlen(line));
} }
struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size) struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size)
{ {
struct adc_message* msg = (struct adc_message*) hub_malloc_zero(sizeof(struct adc_message)); struct adc_message* msg = (struct adc_message*) msg_malloc_zero(sizeof(struct adc_message));
if (!msg) if (!msg)
return NULL; /* OOM */ return NULL; /* OOM */
@@ -465,7 +535,7 @@ struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size)
if (!adc_msg_grow(msg, size+1)) if (!adc_msg_grow(msg, size+1))
{ {
hub_free(msg); msg_free(msg);
return NULL; /* OOM */ return NULL; /* OOM */
} }
@@ -484,7 +554,11 @@ struct adc_message* adc_msg_construct(fourcc_t fourcc, size_t size)
msg->cmd = fourcc; msg->cmd = fourcc;
msg->priority = 0; msg->priority = 0;
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(msg);
#endif
return msg; return msg;
} }
@@ -624,12 +698,20 @@ void adc_msg_terminate(struct adc_message* cmd)
adc_msg_cache_append(cmd, "\n", 1); adc_msg_cache_append(cmd, "\n", 1);
} }
ADC_MSG_ASSERT(cmd); ADC_MSG_ASSERT(cmd);
#ifdef MSG_MEMORY_DEBUG
adc_msg_protect(cmd);
#endif
} }
/* FIXME: this looks bogus */ /* FIXME: this looks bogus */
void adc_msg_unterminate(struct adc_message* cmd) void adc_msg_unterminate(struct adc_message* cmd)
{ {
ADC_MSG_ASSERT(cmd); ADC_MSG_ASSERT(cmd);
#ifdef MSG_MEMORY_DEBUG
adc_msg_unprotect(cmd);
#endif
if (cmd->length > 0 && cmd->cache[cmd->length-1] == '\n') if (cmd->length > 0 && cmd->cache[cmd->length-1] == '\n')
{ {
@@ -654,6 +736,27 @@ int adc_msg_add_named_argument(struct adc_message* cmd, const char prefix[2], co
return ret; return ret;
} }
int adc_msg_add_named_argument_string(struct adc_message* cmd, const char prefix[2], const char* string)
{
char* escaped = adc_msg_escape(string);
int ret = adc_msg_add_named_argument(cmd, prefix, escaped);
hub_free(escaped);
return ret;
}
int adc_msg_add_named_argument_int(struct adc_message* cmd, const char prefix[2], int num)
{
const char* s = uhub_itoa(num);
int ret = adc_msg_add_named_argument(cmd, prefix, s);
return ret;
}
int adc_msg_add_named_argument_uint64(struct adc_message* cmd, const char prefix[2], uint64_t num)
{
const char* s = uhub_ulltoa(num);
int ret = adc_msg_add_named_argument(cmd, prefix, s);
return ret;
}
int adc_msg_add_argument(struct adc_message* cmd, const char* string) int adc_msg_add_argument(struct adc_message* cmd, const char* string)
{ {
@@ -673,16 +776,15 @@ char* adc_msg_get_argument(struct adc_message* cmd, int offset)
char* end; char* end;
char* argument; char* argument;
int count = 0; int count = 0;
ADC_MSG_ASSERT(cmd); ADC_MSG_ASSERT(cmd);
adc_msg_unterminate(cmd); adc_msg_unterminate(cmd);
start = strchr(&cmd->cache[adc_msg_get_arg_offset(cmd)-1], ' '); start = strchr(&cmd->cache[adc_msg_get_arg_offset(cmd)-1], ' ');
while (start) while (start)
{ {
end = strchr(&start[1], ' '); end = strchr(&start[1], ' ');
if (count == offset) if (count == offset)
{ {
if (end) if (end)
@@ -692,21 +794,27 @@ char* adc_msg_get_argument(struct adc_message* cmd, int offset)
else else
{ {
argument = hub_strdup(&start[1]); argument = hub_strdup(&start[1]);
if (argument[strlen(argument)-1] == '\n') if (argument && argument[strlen(argument)-1] == '\n')
argument[strlen(argument)-1] = 0; argument[strlen(argument)-1] = 0;
} }
if (!argument)
return 0; // FIXME: OOM
if (*argument) if (*argument)
{ {
adc_msg_terminate(cmd); adc_msg_terminate(cmd);
return argument; return argument;
} }
else
{
hub_free(argument);
}
} }
count++; count++;
start = end; start = end;
} }
adc_msg_terminate(cmd); adc_msg_terminate(cmd);
return 0; return 0;
} }
@@ -781,7 +889,7 @@ int adc_msg_unescape_length(const char* str)
char* adc_msg_unescape(const char* string) char* adc_msg_unescape(const char* string)
{ {
char* new_string = hub_malloc(adc_msg_unescape_length(string)+1); char* new_string = msg_malloc(adc_msg_unescape_length(string)+1);
char* ptr = (char*) new_string; char* ptr = (char*) new_string;
char* str = (char*) string; char* str = (char*) string;
int escaped = 0; int escaped = 0;

View File

@@ -173,6 +173,22 @@ extern int adc_msg_add_argument(struct adc_message* cmd, const char* string);
*/ */
extern int adc_msg_add_named_argument(struct adc_message* cmd, const char prefix[2], const char* string); extern int adc_msg_add_named_argument(struct adc_message* cmd, const char prefix[2], const char* string);
/**
* Append a string as a named argument.
* The string will automatcally be escaped, if you do not wish to escape th string use adc_msg_add_named_argument() instead.
*
* @arg prefix a 2 character argument prefix
* @arg string must NOT be escaped
* @return 0 if successful, or -1 if an error occured (out of memory).
*/
extern int adc_msg_add_named_argument_string(struct adc_message* cmd, const char prefix[2], const char* string);
/**
* Append an integer as a named argument.
*/
extern int adc_msg_add_named_argument_int(struct adc_message* cmd, const char prefix[2], int integer);
extern int adc_msg_add_named_argument_uint64(struct adc_message* cmd, const char prefix[2], uint64_t num);
/** /**
* Convert a ADC command escaped string to a regular string. * Convert a ADC command escaped string to a regular string.
* @return string or NULL if out of memory * @return string or NULL if out of memory

View File

@@ -88,19 +88,31 @@ struct sid_pool
struct sid_pool* sid_pool_create(sid_t max) struct sid_pool* sid_pool_create(sid_t max)
{ {
struct sid_pool* pool = hub_malloc(sizeof(struct sid_pool)); struct sid_pool* pool = hub_malloc(sizeof(struct sid_pool));
if (!pool)
return 0;
pool->min = 1; pool->min = 1;
pool->max = max + 1; pool->max = max + 1;
pool->count = 0; pool->count = 0;
pool->map = hub_malloc_zero(sizeof(struct hub_user*) * pool->max); pool->map = hub_malloc_zero(sizeof(struct hub_user*) * pool->max);
if (!pool->map)
{
hub_free(pool);
return 0;
}
pool->map[0] = (struct hub_user*) pool; /* hack to reserve the first sid. */ pool->map[0] = (struct hub_user*) pool; /* hack to reserve the first sid. */
#ifdef DEBUG_SID
LOG_DUMP("SID_POOL: max=%d", (int) pool->max); LOG_DUMP("SID_POOL: max=%d", (int) pool->max);
#endif
return pool; return pool;
} }
void sid_pool_destroy(struct sid_pool* pool) void sid_pool_destroy(struct sid_pool* pool)
{ {
#ifdef DEBUG_SID
LOG_DUMP("SID_POOL: destroying, current allocs=%d", (int) pool->count); LOG_DUMP("SID_POOL: destroying, current allocs=%d", (int) pool->count);
#endif
hub_free(pool->map); hub_free(pool->map);
hub_free(pool); hub_free(pool);
} }
@@ -110,14 +122,18 @@ sid_t sid_alloc(struct sid_pool* pool, struct hub_user* user)
sid_t n = (++pool->count); sid_t n = (++pool->count);
for (; (pool->map[n % pool->max]); n++) ; for (; (pool->map[n % pool->max]); n++) ;
#ifdef DEBUG_SID
LOG_DUMP("SID_ALLOC: %d, user=%p", (int) n, user); LOG_DUMP("SID_ALLOC: %d, user=%p", (int) n, user);
#endif
pool->map[n] = user; pool->map[n] = user;
return n; return n;
} }
void sid_free(struct sid_pool* pool, sid_t sid) void sid_free(struct sid_pool* pool, sid_t sid)
{ {
#ifdef DEBUG_SID
LOG_DUMP("SID_FREE: %d", (int) sid); LOG_DUMP("SID_FREE: %d", (int) sid);
#endif
pool->map[sid] = 0; pool->map[sid] = 0;
pool->count--; pool->count--;
} }

View File

@@ -179,26 +179,18 @@ static int acl_parse_line(char* line, int line_count, void* ptr_data)
char* pos; char* pos;
struct acl_handle* handle = (struct acl_handle*) ptr_data; struct acl_handle* handle = (struct acl_handle*) ptr_data;
int ret; int ret;
if ((pos = strchr(line, '#')) != NULL) if ((pos = strchr(line, '#')) != NULL)
{ {
pos[0] = 0; pos[0] = 0;
} }
line = strip_white_space(line);
if (!*line) if (!*line)
return 0; return 0;
LOG_DEBUG("acl_parse_line(): '%s'", line);
line = strip_white_space(line);
if (!*line)
{
LOG_FATAL("ACL parse error on line %d", line_count);
return -1;
}
LOG_DEBUG("acl_parse_line: '%s'", line); LOG_DEBUG("acl_parse_line: '%s'", line);
ACL_ADD_USER("bot", handle->users, cred_bot); ACL_ADD_USER("bot", handle->users, cred_bot);
ACL_ADD_USER("user_admin", handle->users, cred_admin); ACL_ADD_USER("user_admin", handle->users, cred_admin);
ACL_ADD_USER("user_super", handle->users, cred_super); ACL_ADD_USER("user_super", handle->users, cred_super);
@@ -210,7 +202,7 @@ static int acl_parse_line(char* line, int line_count, void* ptr_data)
ACL_ADD_BOOL("ban_cid", handle->cids); ACL_ADD_BOOL("ban_cid", handle->cids);
ACL_ADD_ADDR("deny_ip", handle->networks); ACL_ADD_ADDR("deny_ip", handle->networks);
ACL_ADD_ADDR("nat_ip", handle->nat_override); ACL_ADD_ADDR("nat_ip", handle->nat_override);
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; return -1;
} }
@@ -363,25 +355,46 @@ int acl_is_user_denied(struct acl_handle* handle, const char* data)
int acl_user_ban_nick(struct acl_handle* handle, const char* nick) int acl_user_ban_nick(struct acl_handle* handle, const char* nick)
{ {
char* data = 0;
struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info)); struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info));
if (!info) if (!info)
{ {
LOG_ERROR("ACL error: Out of memory!"); LOG_ERROR("ACL error: Out of memory!");
return -1; return -1;
} }
list_append(handle->users_banned, hub_strdup(nick));
data = hub_strdup(nick);
if (!data)
{
LOG_ERROR("ACL error: Out of memory!");
hub_free(info);
return -1;
}
list_append(handle->users_banned, data);
return 0; return 0;
} }
int acl_user_ban_cid(struct acl_handle* handle, const char* cid) int acl_user_ban_cid(struct acl_handle* handle, const char* cid)
{ {
char* data;
struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info)); struct hub_user_access_info* info = hub_malloc_zero(sizeof(struct hub_user_access_info));
if (!info) if (!info)
{ {
LOG_ERROR("ACL error: Out of memory!"); LOG_ERROR("ACL error: Out of memory!");
return -1; return -1;
} }
list_append(handle->cids, hub_strdup(cid));
data = hub_strdup(cid);
if (!data)
{
LOG_ERROR("ACL error: Out of memory!");
hub_free(info);
return -1;
}
list_append(handle->cids, data);
return 0; return 0;
} }
@@ -439,12 +452,13 @@ int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address)
*/ */
const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user) const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user)
{ {
char buf[32]; char buf[64];
uint64_t tiger_res[3]; uint64_t tiger_res[3];
static char tiger_buf[MAX_CID_LEN+1]; static char tiger_buf[MAX_CID_LEN+1];
snprintf(buf, 32, "%d%d%d", (int) user->net.tm_connected, (int) user->id.sid, (int) user->net.connection.sd); // FIXME: Generate a better nonce scheme.
snprintf(buf, 64, "%p%d%d", user, (int) user->id.sid, (int) net_con_get_sd(user->connection));
tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res); tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res);
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf); base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
tiger_buf[MAX_CID_LEN] = 0; tiger_buf[MAX_CID_LEN] = 0;

View File

@@ -77,7 +77,7 @@ static struct hub_command* command_create(const char* message)
} }
char* prefix = list_get_first(cmd->args); char* prefix = list_get_first(cmd->args);
if (prefix[0] && prefix[1]) if (prefix && prefix[0] && prefix[1])
{ {
cmd->prefix = hub_strdup(&prefix[1]); cmd->prefix = hub_strdup(&prefix[1]);
cmd->prefix_len = strlen(cmd->prefix); cmd->prefix_len = strlen(cmd->prefix);
@@ -169,7 +169,7 @@ static int command_status(struct hub_info* hub, struct hub_user* user, struct hu
static int command_stats(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_stats(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
char temp[128]; char temp[128];
snprintf(temp, 128, "%zu users, peak: %zu. Network (up/down): %d/%d KB/s, peak: %d/%d KB/s", snprintf(temp, 128, PRINTF_SIZE_T " users, peak: " PRINTF_SIZE_T ". Network (up/down): %d/%d KB/s, peak: %d/%d KB/s",
hub->users->count, hub->users->count,
hub->users->count_peak, hub->users->count_peak,
(int) hub->stats.net_tx / 1024, (int) hub->stats.net_tx / 1024,
@@ -235,6 +235,9 @@ static int command_uptime(struct hub_info* hub, struct hub_user* user, struct hu
static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
char* nick = list_get_first(cmd->args); char* nick = list_get_first(cmd->args);
if (!nick)
return -1; // FIXME: bad syntax.
struct hub_user* target = uman_get_user_by_nick(hub, nick); struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target) if (!target)
@@ -250,6 +253,9 @@ static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_
static int command_ban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_ban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
char* nick = list_get_first(cmd->args); char* nick = list_get_first(cmd->args);
if (!nick)
return -1; // FIXME: bad syntax.
struct hub_user* target = uman_get_user_by_nick(hub, nick); struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target) if (!target)
@@ -290,7 +296,7 @@ static int command_version(struct hub_info* hub, struct hub_user* user, struct h
static int command_myip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) static int command_myip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{ {
char tmp[128]; char tmp[128];
snprintf(tmp, 128, "Your address is \"%s\"", ip_convert_to_string(&user->net.ipaddr)); snprintf(tmp, 128, "Your address is \"%s\"", user_get_address(user));
return command_status(hub, user, cmd, tmp); return command_status(hub, user, cmd, tmp);
} }
@@ -299,12 +305,15 @@ static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub
char tmp[128]; char tmp[128];
char* nick = list_get_first(cmd->args); char* nick = list_get_first(cmd->args);
if (!nick);
return -1; // FIXME: bad syntax/OOM
struct hub_user* target = uman_get_user_by_nick(hub, nick); struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target) if (!target)
return command_status_user_not_found(hub, user, cmd, nick); 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)); snprintf(tmp, 128, "%s has address \"%s\"", nick, user_get_address(user));
return command_status(hub, user, cmd, tmp); return command_status(hub, user, cmd, tmp);
} }
@@ -316,11 +325,17 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub
struct hub_user* u; struct hub_user* u;
int ret = 0; int ret = 0;
if (!address)
return -1; // FIXME: bad syntax.
ret = ip_convert_address_to_range(address, &range); ret = ip_convert_address_to_range(address, &range);
if (!ret) if (!ret)
return command_status(hub, user, cmd, "Invalid IP address/range/mask"); return command_status(hub, user, cmd, "Invalid IP address/range/mask");
users = (struct linked_list*) list_create(); users = (struct linked_list*) list_create();
if (!users)
return -1; // FIXME: OOM
ret = uman_get_user_by_addr(hub, users, &range); ret = uman_get_user_by_addr(hub, users, &range);
if (!ret) if (!ret)
@@ -330,9 +345,15 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub
} }
char tmp[128]; char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d match%s:", cmd->prefix, (int) ret, ((ret != 1) ? "es" : "")); snprintf(tmp, 128, "*** %s: Found %d match%s:", cmd->prefix, ret, ((ret != 1) ? "es" : ""));
char* buffer = hub_malloc(((MAX_NICK_LEN + INET6_ADDRSTRLEN + 5) * ret) + strlen(tmp) + 3); char* buffer = hub_malloc(((MAX_NICK_LEN + INET6_ADDRSTRLEN + 5) * ret) + strlen(tmp) + 3);
if (!buffer)
{
list_destroy(users);
return -1; // FIXME: OOM
}
buffer[0] = 0; buffer[0] = 0;
strcat(buffer, tmp); strcat(buffer, tmp);
strcat(buffer, "\n"); strcat(buffer, "\n");
@@ -342,7 +363,7 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub
{ {
strcat(buffer, u->id.nick); strcat(buffer, u->id.nick);
strcat(buffer, " ("); strcat(buffer, " (");
strcat(buffer, ip_convert_to_string(&u->net.ipaddr)); strcat(buffer, user_get_address(u));
strcat(buffer, ")\n"); strcat(buffer, ")\n");
u = (struct hub_user*) list_get_next(users); u = (struct hub_user*) list_get_next(users);
} }
@@ -350,6 +371,7 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub
send_message(hub, user, buffer); send_message(hub, user, buffer);
hub_free(buffer); hub_free(buffer);
list_destroy(users);
return 0; return 0;
} }
@@ -376,7 +398,7 @@ static int command_history(struct hub_info* hub, struct hub_user* user, struct h
} }
char tmp[128]; char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d message%s:", cmd->prefix, (int) ret, ((ret != 1) ? "s" : "")); snprintf(tmp, 128, "*** %s: Found %d message%s:", cmd->prefix, ret, ((ret != 1) ? "s" : ""));
bufsize = strlen(tmp); bufsize = strlen(tmp);
message = (char*) list_get_first(messages); message = (char*) list_get_first(messages);
while (message) while (message)
@@ -430,11 +452,11 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c
if (search_len) if (search_len)
{ {
sprintf(tmp, "Logged entries: %d, searching for \"%s\"", (int) list_size(messages), search); sprintf(tmp, "Logged entries: " PRINTF_SIZE_T ", searching for \"%s\"", list_size(messages), search);
} }
else else
{ {
sprintf(tmp, "Logged entries: %d", (int) list_size(messages)); sprintf(tmp, "Logged entries: " PRINTF_SIZE_T, list_size(messages));
} }
command_status(hub, user, cmd, tmp); command_status(hub, user, cmd, tmp);
@@ -467,7 +489,7 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c
if (search_len) if (search_len)
{ {
sprintf(tmp, "%d entries shown.", (int) search_hits); sprintf(tmp, PRINTF_SIZE_T " entries shown.", search_hits);
command_status(hub, user, cmd, tmp); command_status(hub, user, cmd, tmp);
} }
@@ -490,7 +512,7 @@ int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* m
/* Parse and validate the command */ /* Parse and validate the command */
struct hub_command* cmd = command_create(message); struct hub_command* cmd = command_create(message);
if (!cmd) return 1; if (!cmd) return 0;
for (n = 0; command_handlers[n].prefix; n++) for (n = 0; command_handlers[n].prefix; n++)
{ {
@@ -524,7 +546,7 @@ int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* m
command_not_found(hub, user, cmd); command_not_found(hub, user, cmd);
command_destroy(cmd); command_destroy(cmd);
return 1; return 0;
} }
static struct commands_handler command_handlers[] = { static struct commands_handler command_handlers[] = {

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -110,6 +110,7 @@
/* default configuration values */ /* default configuration values */
#define DEF_SERVER_BIND_ADDR "any" #define DEF_SERVER_BIND_ADDR "any"
#define DEF_SERVER_PORT 1511 #define DEF_SERVER_PORT 1511
#define DEF_SERVER_BACKLOG 50
#define DEF_HUB_NAME "uhub" #define DEF_HUB_NAME "uhub"
#define DEF_HUB_DESCRIPTION "" #define DEF_HUB_DESCRIPTION ""
#define DEF_HUB_ENABLED 1 #define DEF_HUB_ENABLED 1
@@ -137,6 +138,10 @@
#define DEF_LIMIT_MAX_SHARE 0 #define DEF_LIMIT_MAX_SHARE 0
#define DEF_LIMIT_MIN_SLOTS 0 #define DEF_LIMIT_MIN_SLOTS 0
#define DEF_LIMIT_MAX_SLOTS 0 #define DEF_LIMIT_MAX_SLOTS 0
#define DEF_TLS_ENABLE 0
#define DEF_TLS_REQUIRE 1
#define DEF_TLS_PRIVATE_KEY ""
#define DEF_TLS_CERTIFICATE ""
#define DEF_MSG_HUB_FULL "Hub is full" #define DEF_MSG_HUB_FULL "Hub is full"
#define DEF_MSG_HUB_DISABLED "Hub is disabled" #define DEF_MSG_HUB_DISABLED "Hub is disabled"
#define DEF_MSG_HUB_REGISTERED_USERS_ONLY "Hub is for registered users only" #define DEF_MSG_HUB_REGISTERED_USERS_ONLY "Hub is for registered users only"
@@ -176,6 +181,7 @@ void config_defaults(struct hub_config* config)
DEFAULT_STRING (file_acl, DEF_FILE_ACL); DEFAULT_STRING (file_acl, DEF_FILE_ACL);
DEFAULT_STRING (file_motd, DEF_FILE_MOTD); DEFAULT_STRING (file_motd, DEF_FILE_MOTD);
DEFAULT_INTEGER(server_port, DEF_SERVER_PORT); DEFAULT_INTEGER(server_port, DEF_SERVER_PORT);
DEFAULT_INTEGER(server_listen_backlog, DEF_SERVER_BACKLOG);
DEFAULT_INTEGER(max_users, DEF_MAX_USERS); DEFAULT_INTEGER(max_users, DEF_MAX_USERS);
DEFAULT_INTEGER(max_chat_history, DEF_MAX_CHAT_HISTORY); DEFAULT_INTEGER(max_chat_history, DEF_MAX_CHAT_HISTORY);
DEFAULT_INTEGER(max_logout_log, DEF_MAX_LOGOUT_LOG); DEFAULT_INTEGER(max_logout_log, DEF_MAX_LOGOUT_LOG);
@@ -232,10 +238,10 @@ void config_defaults(struct hub_config* config)
DEFAULT_STRING (msg_user_hub_limit_low, DEF_MSG_USER_HUB_LIMIT_LOW); DEFAULT_STRING (msg_user_hub_limit_low, DEF_MSG_USER_HUB_LIMIT_LOW);
DEFAULT_STRING (msg_user_hub_limit_high, DEF_MSG_USER_HUB_LIMIT_HIGH); DEFAULT_STRING (msg_user_hub_limit_high, DEF_MSG_USER_HUB_LIMIT_HIGH);
DEFAULT_INTEGER(tls_enable, 0); DEFAULT_INTEGER(tls_enable, DEF_TLS_ENABLE);
DEFAULT_INTEGER(tls_require, 0); DEFAULT_INTEGER(tls_require, DEF_TLS_REQUIRE);
DEFAULT_STRING (tls_certificate, ""); DEFAULT_STRING (tls_certificate, DEF_TLS_CERTIFICATE);
DEFAULT_STRING (tls_private_key, ""); DEFAULT_STRING (tls_private_key, DEF_TLS_PRIVATE_KEY);
} }
@@ -245,6 +251,7 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
GET_STR (file_motd); GET_STR (file_motd);
GET_STR (server_bind_addr); GET_STR (server_bind_addr);
GET_INT (server_port); GET_INT (server_port);
GET_INT (server_listen_backlog);
GET_STR (hub_name); GET_STR (hub_name);
GET_STR (hub_description); GET_STR (hub_description);
GET_BOOL(hub_enabled); GET_BOOL(hub_enabled);
@@ -393,6 +400,7 @@ void dump_config(struct hub_config* config, int ignore_defaults)
DUMP_STR (file_motd, DEF_FILE_MOTD); DUMP_STR (file_motd, DEF_FILE_MOTD);
DUMP_STR (server_bind_addr, DEF_SERVER_BIND_ADDR); DUMP_STR (server_bind_addr, DEF_SERVER_BIND_ADDR);
DUMP_INT (server_port, DEF_SERVER_PORT); DUMP_INT (server_port, DEF_SERVER_PORT);
DUMP_INT (server_listen_backlog, DEF_SERVER_BACKLOG);
DUMP_STR (hub_name, DEF_HUB_NAME); DUMP_STR (hub_name, DEF_HUB_NAME);
DUMP_STR (hub_description, DEF_HUB_DESCRIPTION); DUMP_STR (hub_description, DEF_HUB_DESCRIPTION);
DUMP_BOOL(hub_enabled, DEF_HUB_ENABLED); DUMP_BOOL(hub_enabled, DEF_HUB_ENABLED);
@@ -408,6 +416,13 @@ void dump_config(struct hub_config* config, int ignore_defaults)
DUMP_BOOL(low_bandwidth_mode, DEF_LOW_BANDWIDTH_MODE); DUMP_BOOL(low_bandwidth_mode, DEF_LOW_BANDWIDTH_MODE);
DUMP_BOOL(registered_users_only, DEF_REGISTERED_USERS_ONLY); DUMP_BOOL(registered_users_only, DEF_REGISTERED_USERS_ONLY);
#ifdef SSL_SUPPORT
DUMP_BOOL(tls_enable, DEF_TLS_ENABLE);
DUMP_BOOL(tls_require, DEF_TLS_REQUIRE);
DUMP_STR (tls_certificate, DEF_TLS_CERTIFICATE);
DUMP_STR (tls_private_key, DEF_TLS_PRIVATE_KEY);
#endif
/* Limits enforced on users */ /* Limits enforced on users */
DUMP_INT(limit_max_hubs_user, DEF_LIMIT_MAX_HUBS_USER); DUMP_INT(limit_max_hubs_user, DEF_LIMIT_MAX_HUBS_USER);
DUMP_INT(limit_max_hubs_reg, DEF_LIMIT_MAX_HUBS_REG); DUMP_INT(limit_max_hubs_reg, DEF_LIMIT_MAX_HUBS_REG);

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ struct hub_config
{ {
int server_port; /**<<< "Server port to bind to (default: 1511)" */ int server_port; /**<<< "Server port to bind to (default: 1511)" */
char* server_bind_addr; /**<<< "Server bind address (default: '0.0.0.0' or '::')" */ char* server_bind_addr; /**<<< "Server bind address (default: '0.0.0.0' or '::')" */
int server_listen_backlog; /**<<< "Server listen backlog (default: 50)" */
int hub_enabled; /**<<< "Is server enabled (default: 1)" */ int hub_enabled; /**<<< "Is server enabled (default: 1)" */
int show_banner; /**<<< "Show banner on connect (default: 1)" */ int show_banner; /**<<< "Show banner on connect (default: 1)" */
int max_users; /**<<< "Maximum number of users allowed on the hub (default: 500)" */ int max_users; /**<<< "Maximum number of users allowed on the hub (default: 500)" */

View File

@@ -28,10 +28,14 @@
/* Send a broadcast message */ /* Send a broadcast message */
#define UHUB_EVENT_BROADCAST 0x2000 #define UHUB_EVENT_BROADCAST 0x2000
/* Shutdown hub */
#define UHUB_EVENT_HUB_SHUTDOWN 0x3001
/* Statistics, OOM, reconfigure */ /* Statistics, OOM, reconfigure */
#define UHUB_EVENT_STATISTICS 0x4000 #define UHUB_EVENT_STATISTICS 0x4000
#define UHUB_EVENT_OUT_OF_MEMORY 0x4001 #define UHUB_EVENT_OUT_OF_MEMORY 0x4001
#define UHUB_EVENT_RECONFIGURE 0x4002 #define UHUB_EVENT_RECONFIGURE 0x4002
#endif /* HAVE_UHUB_EVENT_ID_H */ #endif /* HAVE_UHUB_EVENT_ID_H */

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -102,12 +102,12 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
if (hub->status == hub_status_disabled && u->state == state_protocol) if (hub->status == hub_status_disabled && u->state == state_protocol)
{ {
on_login_failure(hub, u, status_msg_hub_disabled); on_login_failure(hub, u, status_msg_hub_disabled);
hub_free(arg);
return -1; return -1;
} }
while (arg) while (arg)
{ {
if (strlen(arg) == 6) if (strlen(arg) == 6)
{ {
fourcc_t fourcc = FOURCC(arg[2], arg[3], arg[4], arg[5]); fourcc_t fourcc = FOURCC(arg[2], arg[3], arg[4], arg[5]);
@@ -133,7 +133,7 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
hub_free(arg); hub_free(arg);
arg = adc_msg_get_argument(cmd, index); arg = adc_msg_get_argument(cmd, index);
} }
if (u->state == state_protocol) if (u->state == state_protocol)
{ {
if (index == 0) ok = 0; /* Need to support *SOMETHING*, at least BASE */ if (index == 0) ok = 0; /* Need to support *SOMETHING*, at least BASE */
@@ -141,7 +141,7 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
if (ok) if (ok)
{ {
hub_send_handshake(hub, u); hub_send_handshake(hub, u);
user_set_timeout(u, TIMEOUT_HANDSHAKE); net_con_set_timeout(u->connection, TIMEOUT_HANDSHAKE);
} }
else else
{ {
@@ -150,7 +150,7 @@ int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_mess
ret = -1; ret = -1;
} }
} }
return ret; return ret;
} }
@@ -183,10 +183,27 @@ int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc
char* message = adc_msg_get_argument(cmd, 0); char* message = adc_msg_get_argument(cmd, 0);
int ret = 0; int ret = 0;
int relay = 1; int relay = 1;
if (message[0] == '!' || message[0] == '+') if (!message || !user_is_logged_in(u))
return 0;
if ((cmd->cache[0] == 'B') && (message[0] == '!' || message[0] == '+'))
{ {
relay = command_dipatcher(hub, u, message); /*
* A message such as "++message" is handled as "+message", by removing the first character.
* The first character is removed by memmoving the string one byte to the left.
*/
if (message[1] == message[0])
{
relay = 1;
int offset = adc_msg_get_arg_offset(cmd);
memmove(cmd->cache+offset+1, cmd->cache+offset+2, cmd->length - offset);
cmd->length--;
}
else
{
relay = command_dipatcher(hub, u, message);
}
} }
if (hub->config->chat_is_privileged && !user_is_protected(u) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F')) if (hub->config->chat_is_privileged && !user_is_protected(u) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F'))
@@ -194,7 +211,7 @@ int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc
relay = 0; relay = 0;
} }
if (relay && user_is_logged_in(u)) if (relay)
{ {
/* adc_msg_remove_named_argument(cmd, "PM"); */ /* adc_msg_remove_named_argument(cmd, "PM"); */
if (cmd->cache[0] == 'B') if (cmd->cache[0] == 'B')
@@ -400,7 +417,20 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message
user_destroy(user); user_destroy(user);
break; break;
} }
case UHUB_EVENT_HUB_SHUTDOWN:
{
struct hub_user* u = (struct hub_user*) list_get_first(hub->users->list);
while (u)
{
uman_remove(hub, u);
user_destroy(u);
u = (struct hub_user*) list_get_first(hub->users->list);
}
break;
}
default: default:
/* FIXME: ignored */ /* FIXME: ignored */
break; break;
@@ -448,25 +478,11 @@ struct hub_info* hub_start_service(struct hub_config* config)
net_address_to_string(AF_INET6, &((struct sockaddr_in6*) &addr)->sin6_addr, address_buf, INET6_ADDRSTRLEN); net_address_to_string(AF_INET6, &((struct sockaddr_in6*) &addr)->sin6_addr, address_buf, INET6_ADDRSTRLEN);
} }
#ifdef LIBEVENT_1_4
hub->evbase = event_base_new();
#else
hub->evbase = event_init();
#endif
if (!hub->evbase)
{
LOG_ERROR("Unable to initialize libevent.");
hub_free(hub);
return 0;
}
LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port); LOG_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); server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
if (server_tcp == -1) if (server_tcp == -1)
{ {
event_base_free(hub->evbase);
hub_free(hub); hub_free(hub);
return 0; return 0;
} }
@@ -474,7 +490,6 @@ struct hub_info* hub_start_service(struct hub_config* config)
ret = net_set_reuseaddress(server_tcp, 1); ret = net_set_reuseaddress(server_tcp, 1);
if (ret == -1) if (ret == -1)
{ {
event_base_free(hub->evbase);
hub_free(hub); hub_free(hub);
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
@@ -483,7 +498,6 @@ struct hub_info* hub_start_service(struct hub_config* config)
ret = net_set_nonblocking(server_tcp, 1); ret = net_set_nonblocking(server_tcp, 1);
if (ret == -1) if (ret == -1)
{ {
event_base_free(hub->evbase);
hub_free(hub); hub_free(hub);
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
@@ -493,42 +507,58 @@ struct hub_info* hub_start_service(struct hub_config* config)
if (ret == -1) if (ret == -1)
{ {
LOG_FATAL("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error())); 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); hub_free(hub);
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
ret = net_listen(server_tcp, SERVER_BACKLOG); ret = net_listen(server_tcp, config->server_listen_backlog);
if (ret == -1) if (ret == -1)
{ {
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); hub_free(hub);
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
hub->fd_tcp = server_tcp; #ifdef SSL_SUPPORT
if (config->tls_enable)
{
hub->ssl_method = SSLv23_method(); /* TLSv1_method() */
hub->ssl_ctx = SSL_CTX_new(hub->ssl_method);
/* Disable SSLv2 */
SSL_CTX_set_options(hub->ssl_ctx, SSL_OP_NO_SSLv2);
if (SSL_CTX_use_certificate_file(hub->ssl_ctx, config->tls_certificate, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
}
if (SSL_CTX_use_PrivateKey_file(hub->ssl_ctx, config->tls_private_key, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
}
if (SSL_CTX_check_private_key(hub->ssl_ctx) != 1)
{
LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
LOG_INFO("Enabling TLS, using certificate: %s, private key: %s", config->tls_certificate, config->tls_private_key);
}
#endif
hub->config = config; hub->config = config;
hub->users = NULL; hub->users = NULL;
if (uman_init(hub) == -1) if (uman_init(hub) == -1)
{ {
hub_free(hub); hub_free(hub);
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
event_set(&hub->ev_accept, hub->fd_tcp, EV_READ | EV_PERSIST, net_on_accept, hub);
event_base_set(hub->evbase, &hub->ev_accept);
if (event_add(&hub->ev_accept, NULL) == -1)
{
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
return 0;
}
if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1) if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
{ {
@@ -537,7 +567,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
hub->recvbuf = hub_malloc(MAX_RECV_BUF); hub->recvbuf = hub_malloc(MAX_RECV_BUF);
hub->sendbuf = hub_malloc(MAX_SEND_BUF); hub->sendbuf = hub_malloc(MAX_SEND_BUF);
if (!hub->recvbuf || !hub->sendbuf) if (!hub->recvbuf || !hub->sendbuf)
@@ -566,6 +596,9 @@ struct hub_info* hub_start_service(struct hub_config* config)
hub->status = hub_status_running; hub->status = hub_status_running;
hub->server = net_con_create();
net_con_initialize(hub->server, server_tcp, net_on_accept, hub, NET_EVENT_READ);
g_hub = hub; g_hub = hub;
return hub; return hub;
} }
@@ -573,14 +606,16 @@ struct hub_info* hub_start_service(struct hub_config* config)
void hub_shutdown_service(struct hub_info* hub) void hub_shutdown_service(struct hub_info* hub)
{ {
LOG_TRACE("hub_shutdown_service()"); LOG_DEBUG("hub_shutdown_service()");
event_queue_shutdown(hub->queue); event_queue_shutdown(hub->queue);
#ifdef USE_LIBEVENT
event_del(&hub->ev_accept); event_del(&hub->ev_accept);
net_close(hub->fd_tcp); #endif
net_con_close(hub->server);
hub_free(hub->server);
uman_shutdown(hub); uman_shutdown(hub);
hub->status = hub_status_stopped; hub->status = hub_status_stopped;
event_base_free(hub->evbase);
hub_free(hub->sendbuf); hub_free(hub->sendbuf);
hub_free(hub->recvbuf); hub_free(hub->recvbuf);
hub_chat_history_clear(hub); hub_chat_history_clear(hub);
@@ -616,10 +651,10 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp); adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp);
hub_free(tmp); hub_free(tmp);
} }
/* (Re-)read the message of the day */ /* (Re-)read the message of the day */
hub->command_motd = 0; hub->command_motd = 0;
fd = open(hub->config->file_motd, 0); fd = (hub->config->file_motd && *hub->config->file_motd) ? open(hub->config->file_motd, 0) : -1;
if (fd != -1) if (fd != -1)
{ {
ret = read(fd, buf, MAX_RECV_BUF); ret = read(fd, buf, MAX_RECV_BUF);
@@ -628,22 +663,18 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
buf[ret] = 0; buf[ret] = 0;
tmp = adc_msg_escape(buf); tmp = adc_msg_escape(buf);
hub->command_motd = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp)); hub->command_motd = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp));
adc_msg_add_argument(hub->command_motd, tmp); adc_msg_add_argument(hub->command_motd, tmp);
hub_free(tmp); hub_free(tmp);
}
else
{
} }
close(fd); close(fd);
} }
hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT)); hub->command_support = adc_msg_construct(ADC_CMD_ISUP, 6 + strlen(ADC_PROTO_SUPPORT));
if (hub->command_support) if (hub->command_support)
{ {
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT); adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
} }
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(server)); hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(server));
if (hub->command_banner) if (hub->command_banner)
{ {
@@ -652,7 +683,7 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
adc_msg_add_argument(hub->command_banner, tmp); adc_msg_add_argument(hub->command_banner, tmp);
hub_free(tmp); hub_free(tmp);
} }
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled); hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
hub_free(server); hub_free(server);
} }
@@ -662,10 +693,10 @@ void hub_free_variables(struct hub_info* hub)
{ {
adc_msg_free(hub->command_info); adc_msg_free(hub->command_info);
adc_msg_free(hub->command_banner); adc_msg_free(hub->command_banner);
if (hub->command_motd) if (hub->command_motd)
adc_msg_free(hub->command_motd); adc_msg_free(hub->command_motd);
adc_msg_free(hub->command_support); adc_msg_free(hub->command_support);
} }
@@ -931,27 +962,6 @@ size_t hub_get_min_hubs_op(struct hub_info* hub)
return hub->config->limit_min_hubs_op; return hub->config->limit_min_hubs_op;
} }
void hub_event_loop(struct hub_info* hub)
{
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 || hub->status == hub_status_disabled);
}
void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user) void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
{ {
struct event_data post; struct event_data post;
@@ -966,11 +976,42 @@ void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
} }
} }
void hub_disconnect_all(struct hub_info* hub)
{
struct event_data post;
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_HUB_SHUTDOWN;
post.ptr = 0;
event_queue_post(hub->queue, &post);
}
void hub_event_loop(struct hub_info* hub)
{
do
{
net_backend_process();
event_queue_process(hub->queue);
}
while (hub->status == hub_status_running || hub->status == hub_status_disabled);
if (hub->status == hub_status_shutdown)
{
LOG_DEBUG("Removing all users...");
event_queue_process(hub->queue);
event_queue_process(hub->queue);
hub_disconnect_all(hub);
event_queue_process(hub->queue);
hub->status = hub_status_stopped;
}
}
void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason) void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason)
{ {
struct event_data post; struct event_data post;
int need_notify = 0; int need_notify = 0;
/* is user already being disconnected ? */ /* is user already being disconnected ? */
if (user_is_disconnecting(user)) if (user_is_disconnecting(user))
{ {
@@ -978,11 +1019,13 @@ void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason
} }
/* stop reading from user */ /* stop reading from user */
net_shutdown_r(user->net.connection.sd); net_shutdown_r(net_con_get_sd(user->connection));
net_con_close(user->connection);
user->connection = 0;
LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state); LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state);
need_notify = user_is_logged_in(user); need_notify = user_is_logged_in(user) && hub->status == hub_status_running;
user->quit_reason = reason; user->quit_reason = reason;
user_set_state(user, state_cleanup); user_set_state(user, state_cleanup);
@@ -1006,7 +1049,7 @@ void hub_logout_log(struct hub_info* hub, struct hub_user* user)
loginfo->time = time(NULL); loginfo->time = time(NULL);
strcpy(loginfo->cid, user->id.cid); strcpy(loginfo->cid, user->id.cid);
strcpy(loginfo->nick, user->id.nick); strcpy(loginfo->nick, user->id.nick);
memcpy(&loginfo->addr, &user->net.ipaddr, sizeof(struct ip_addr_encap)); memcpy(&loginfo->addr, &user->id.addr, sizeof(struct ip_addr_encap));
loginfo->reason = user->quit_reason; loginfo->reason = user->quit_reason;
list_append(hub->logout_info, loginfo); list_append(hub->logout_info, loginfo);

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -90,12 +90,13 @@ struct hub_logout_info
struct hub_info struct hub_info
{ {
int fd_tcp; struct net_connection* server;
#ifdef USE_LIBEVENT
struct event ev_accept; struct event ev_accept;
struct event ev_timer; struct event ev_timer;
#endif
struct hub_stats stats; struct hub_stats stats;
struct event_queue* queue; struct event_queue* queue;
struct event_base* evbase;
struct hub_config* config; struct hub_config* config;
struct hub_user_manager* users; struct hub_user_manager* users;
struct acl_handle* acl; struct acl_handle* acl;

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,26 +22,26 @@
static void log_user_login(struct hub_user* u) static void log_user_login(struct hub_user* u)
{ {
const char* cred = get_user_credential_string(u->credentials); const char* cred = get_user_credential_string(u->credentials);
const char* addr = ip_convert_to_string(&u->net.ipaddr); const char* addr = user_get_address(u);
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); 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) 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* addr = user_get_address(u);
const char* message = hub_get_status_message_log(u->hub, msg); 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); 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) static void log_user_logout(struct hub_user* u, const char* message)
{ {
const char* addr = ip_convert_to_string(&u->net.ipaddr); const char* addr = user_get_address(u);
LOG_USER("Logout %s/%s %s \"%s\" (%s)", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message); 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) static void log_user_nick_change(struct hub_user* u, const char* nick)
{ {
const char* addr = ip_convert_to_string(&u->net.ipaddr); const char* addr = user_get_address(u);
LOG_USER("NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick); LOG_USER("NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick);
} }
@@ -67,9 +67,9 @@ void on_login_success(struct hub_info* hub, struct hub_user* u)
/* Send message of the day (if any) */ /* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */ if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(hub, u); hub_send_motd(hub, u);
/* reset to idle timeout */ /* reset timeout */
user_set_timeout(u, TIMEOUT_IDLE); net_con_clear_timeout(u->connection);
} }
void on_login_failure(struct hub_info* hub, struct hub_user* u, enum status_message msg) void on_login_failure(struct hub_info* hub, struct hub_user* u, enum status_message msg)

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -20,11 +20,6 @@
#include "uhub.h" #include "uhub.h"
#include "hubio.h" #include "hubio.h"
// #define SEND_CHUNKS 1
/* FIXME: This should not be needed! */
extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ #ifdef DEBUG_SENDQ
static void debug_msg(const char* prefix, struct adc_message* msg) static void debug_msg(const char* prefix, struct adc_message* msg)
{ {
@@ -146,58 +141,21 @@ void hub_sendq_remove(struct hub_sendq* q, struct adc_message* msg)
q->offset = 0; q->offset = 0;
} }
int hub_sendq_send(struct hub_sendq* q, hub_recvq_write w, void* data) int hub_sendq_send(struct hub_sendq* q, struct hub_user* user)
{ {
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); struct adc_message* msg = list_get_first(q->queue);
while (msg) if (!msg) return 0;
{
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); int ret = net_con_send(user->connection, msg->cache + q->offset, msg->length - q->offset);
/* Send as much as possible */
ret = w(data, sbuf, bytes);
if (ret > 0) if (ret > 0)
{ {
#ifdef SSL_SUPPORT q->offset += ret;
q->last_write_n = ret; if (msg->length - q->offset > 0)
#endif return 0;
/* Remove messages sent */ hub_sendq_remove(q, msg);
offset = q->offset; return 1;
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; return ret;
} }

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -58,10 +58,9 @@ extern void hub_sendq_add(struct hub_sendq*, struct adc_message* msg);
/** /**
* Process the send queue, and send as many messages as possible. * Process the send queue, and send as many messages as possible.
* @returns the number of bytes sent. * @returns -1 on error, 0 if unable to send more, 1 if more can be sent.
* FIXME: send error not handled here!
*/ */
extern int hub_sendq_send(struct hub_sendq*, hub_recvq_write, void* data); extern int hub_sendq_send(struct hub_sendq*, struct hub_user*);
/** /**
* @returns 1 if send queue is empty, 0 otherwise. * @returns 1 if send queue is empty, 0 otherwise.

View File

@@ -46,8 +46,11 @@ static int set_feature_cast_supports(struct hub_user* u, struct adc_message* cmd
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_SUPPORT)) if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_SUPPORT))
{ {
tmp = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SUPPORT); tmp = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SUPPORT);
if (!tmp)
return -1; // FIXME: OOM
user_clear_feature_cast_support(u); user_clear_feature_cast_support(u);
it = tmp; it = tmp;
while (strlen(it) > 4) while (strlen(it) > 4)
{ {
@@ -186,13 +189,13 @@ static int check_required_login_flags(struct hub_info* hub, struct hub_user* use
*/ */
int check_network(struct hub_info* hub, struct hub_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->net.ipaddr); const char* address = user_get_address(user);
/* Check for NAT override address */ /* Check for NAT override address */
if (acl_is_ip_nat_override(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); 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) if (client_given_ip && strcmp(client_given_ip, "0.0.0.0") != 0)
{ {
user_set_nat_override(user); user_set_nat_override(user);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR); adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR);
@@ -655,7 +658,6 @@ int hub_perform_login_checks(struct hub_info* hub, struct hub_user* user, struct
INF_CHECK(check_user_agent, hub, user, cmd); INF_CHECK(check_user_agent, hub, user, cmd);
INF_CHECK(check_acl, hub, user, cmd); INF_CHECK(check_acl, hub, user, cmd);
INF_CHECK(check_logged_in, hub, user, cmd); INF_CHECK(check_logged_in, hub, user, cmd);
return 0; return 0;
} }

View File

@@ -33,7 +33,7 @@ static const char* arg_pid = 0;
static int arg_log_syslog = 0; static int arg_log_syslog = 0;
#ifndef WIN32 #if !defined(WIN32) && defined(USE_LIBEVENT)
void hub_handle_signal(int fd, short events, void* arg) void hub_handle_signal(int fd, short events, void* arg)
{ {
struct hub_info* hub = (struct hub_info*) arg; struct hub_info* hub = (struct hub_info*) arg;
@@ -81,7 +81,6 @@ void setup_signal_handlers(struct hub_info* hub)
for (i = 0; signals[i]; i++) for (i = 0; signals[i]; i++)
{ {
signal_set(&signal_events[i], signals[i], hub_handle_signal, hub); signal_set(&signal_events[i], signals[i], hub_handle_signal, hub);
event_base_set(hub->evbase, &signal_events[i]);
if (signal_add(&signal_events[i], NULL)) if (signal_add(&signal_events[i], NULL))
{ {
LOG_ERROR("Error setting signal handler %d", signals[i]); LOG_ERROR("Error setting signal handler %d", signals[i]);
@@ -98,7 +97,7 @@ void shutdown_signal_handlers(struct hub_info* hub)
} }
} }
#endif /* WIN32 */ #endif /* !WIN32 && USE_LIBEVENT*/
int main_loop() int main_loop()
@@ -134,7 +133,7 @@ int main_loop()
hub = hub_start_service(&configuration); hub = hub_start_service(&configuration);
if (!hub) if (!hub)
return -1; return -1;
#ifndef WIN32 #if !defined(WIN32) && defined(USE_LIBEVENT)
setup_signal_handlers(hub); setup_signal_handlers(hub);
#endif #endif
} }
@@ -147,9 +146,9 @@ int main_loop()
acl_shutdown(&acl); acl_shutdown(&acl);
free_config(&configuration); free_config(&configuration);
} while(hub->status != hub_status_shutdown); } while (hub->status == hub_status_restart);
#ifndef WIN32 #if !defined(WIN32) && defined(USE_LIBEVENT)
shutdown_signal_handlers(hub); shutdown_signal_handlers(hub);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -17,8 +17,9 @@
* *
*/ */
#include "uhub.h" #include <uhub.h>
#include "hubio.h" #include "hubio.h"
#include "probe.h"
/* FIXME: This should not be needed! */ /* FIXME: This should not be needed! */
extern struct hub_info* g_hub; extern struct hub_info* g_hub;
@@ -52,105 +53,26 @@ void debug_sendq_recv(struct hub_user* user, int received, int max, const char*
} }
#endif #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) int handle_net_read(struct hub_user* user)
{ {
static char buf[MAX_RECV_BUF]; static char buf[MAX_RECV_BUF];
struct hub_recvq* q = user->net.recv_queue; struct hub_recvq* q = user->recv_queue;
size_t buf_size = hub_recvq_get(q, buf, MAX_RECV_BUF); 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); ssize_t size = net_con_recv(user->connection, buf, MAX_RECV_BUF);
if (size > 0) if (size > 0)
buf_size += size; buf_size += size;
if (size == -1) if (size < 0)
{ {
if (net_error() == EWOULDBLOCK || net_error() == EINTR) if (size == -1)
return 0; return quit_disconnected;
else
return quit_socket_error; return quit_socket_error;
} }
else if (size == 0) else if (size == 0)
{ {
return quit_disconnected; return 0;
} }
else else
{ {
@@ -179,7 +101,6 @@ int handle_net_read(struct hub_user* user)
if (hub_handle_message(g_hub, user, start, (pos - start)) == -1) if (hub_handle_message(g_hub, user, start, (pos - start)) == -1)
{ {
return quit_protocol_error; return quit_protocol_error;
break;
} }
} }
} }
@@ -190,16 +111,17 @@ int handle_net_read(struct hub_user* user)
start = pos; start = pos;
} }
if (lastPos) if (lastPos || remaining)
{ {
if (remaining < g_hub->config->max_recv_buffer) if (remaining < g_hub->config->max_recv_buffer)
{ {
hub_recvq_set(q, lastPos, remaining); hub_recvq_set(q, lastPos ? lastPos : buf, remaining);
} }
else else
{ {
hub_recvq_set(q, 0, 0); hub_recvq_set(q, 0, 0);
user_flag_set(user, flag_maxbuf); user_flag_set(user, flag_maxbuf);
LOG_WARN("Received message past max_recv_buffer, dropping message.");
} }
} }
else else
@@ -212,17 +134,18 @@ int handle_net_read(struct hub_user* user)
int handle_net_write(struct hub_user* user) int handle_net_write(struct hub_user* user)
{ {
while (hub_sendq_get_bytes(user->net.send_queue)) int ret = 0;
while (hub_sendq_get_bytes(user->send_queue))
{ {
int ret = hub_sendq_send(user->net.send_queue, net_user_send, user); ret = hub_sendq_send(user->send_queue, user);
if (ret == -2)
break;
if (ret <= 0) if (ret <= 0)
return quit_socket_error; break;
} }
if (hub_sendq_get_bytes(user->net.send_queue)) if (ret < 0)
return quit_socket_error;
if (hub_sendq_get_bytes(user->send_queue))
{ {
user_net_io_want_write(user); user_net_io_want_write(user);
} }
@@ -233,77 +156,63 @@ int handle_net_write(struct hub_user* user)
return 0; return 0;
} }
void net_event(int fd, short ev, void *arg) void net_event(struct net_connection* con, int event, void *arg)
{ {
struct hub_user* user = (struct hub_user*) arg; struct hub_user* user = (struct hub_user*) arg;
int flag_close = 0; int flag_close = 0;
#ifdef DEBUG_SENDQ #ifdef DEBUG_SENDQ
LOG_TRACE("net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg); LOG_TRACE("net_event() : fd=%d, ev=%d, arg=%p", fd, (int) event, arg);
#endif #endif
if (ev & EV_TIMEOUT) if (event == NET_EVENT_SOCKERROR)
{
hub_disconnect_user(g_hub, user, quit_socket_error);
return;
}
else if (event == NET_EVENT_CLOSED)
{
hub_disconnect_user(g_hub, user, quit_disconnected);
return;
}
else if (event == NET_EVENT_TIMEOUT)
{ {
if (user_is_connecting(user)) if (user_is_connecting(user))
{ {
flag_close = quit_timeout; hub_disconnect_user(g_hub, user, quit_timeout);
} return;
else
{
// FIXME: hub is not neccesarily set!
// hub_send_ping(hub, user);
} }
} }
if (ev & EV_READ) if (event & NET_EVENT_READ)
{ {
flag_close = handle_net_read(user); flag_close = handle_net_read(user);
if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
} }
else if (ev & EV_WRITE)
if (event & NET_EVENT_WRITE)
{ {
flag_close = handle_net_write(user); flag_close = handle_net_write(user);
} if (flag_close)
{
if (flag_close) hub_disconnect_user(g_hub, user, flag_close);
{ return;
hub_disconnect_user(g_hub, user, flag_close); }
return;
} }
} }
void net_on_accept(struct net_connection* con, int event, void *arg)
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_info* hub = (struct hub_info*) arg;
struct hub_user* user = 0; struct hub_probe* probe = 0;
struct ip_addr_encap ipaddr; struct ip_addr_encap ipaddr;
const char* addr; const char* addr;
int server_fd = net_con_get_sd(con);
for (;;) for (;;)
{ {
int fd = net_accept(server_fd, &ipaddr); int fd = net_accept(server_fd, &ipaddr);
@@ -319,12 +228,12 @@ void net_on_accept(int server_fd, short ev, void *arg)
break; break;
} }
} }
addr = ip_convert_to_string(&ipaddr); addr = ip_convert_to_string(&ipaddr);
/* FIXME: Should have a plugin log this */ /* FIXME: Should have a plugin log this */
LOG_TRACE("Got connection from %s", addr); LOG_TRACE("Got connection from %s", addr);
/* FIXME: A plugin should perform this check: is IP banned? */ /* FIXME: A plugin should perform this check: is IP banned? */
if (acl_is_ip_banned(hub->acl, addr)) if (acl_is_ip_banned(hub->acl, addr))
{ {
@@ -332,19 +241,14 @@ void net_on_accept(int server_fd, short ev, void *arg)
net_close(fd); net_close(fd);
continue; continue;
} }
user = user_create(hub, fd); probe = probe_create(hub, fd, &ipaddr);
if (!user) if (!probe)
{ {
LOG_ERROR("Unable to create user after socket accepted. Out of memory?"); LOG_ERROR("Unable to create probe after socket accepted. Out of memory?");
net_close(fd); net_close(fd);
break; break;
} }
/* Store IP address in user object */
memcpy(&user->net.ipaddr, &ipaddr, sizeof(ipaddr));
prepare_user_net(hub, user);
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,9 +23,8 @@
/** /**
* Network callback to accept incoming connections. * Network callback to accept incoming connections.
*/ */
extern void net_on_accept(int fd, short ev, void *arg); extern void net_on_accept(struct net_connection* con, int event, void *arg);
extern void net_event(struct net_connection* con, int event, void *arg);
extern void net_event(int fd, short ev, void *arg);
extern int handle_net_read(struct hub_user* user); extern int handle_net_read(struct hub_user* user);
extern int handle_net_write(struct hub_user* user); extern int handle_net_write(struct hub_user* user);

120
src/core/probe.c Normal file
View File

@@ -0,0 +1,120 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#include "probe.h"
#define PROBE_RECV_SIZE 12
static char probe_recvbuf[PROBE_RECV_SIZE];
static void probe_net_event(struct net_connection* con, int events, void *arg)
{
struct hub_probe* probe = (struct hub_probe*) net_con_get_ptr(con);
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED || events == NET_EVENT_TIMEOUT)
{
probe_destroy(probe);
return;
}
if (events & NET_EVENT_READ)
{
int bytes = net_con_peek(con, probe_recvbuf, PROBE_RECV_SIZE);
if (bytes < 0)
{
probe_destroy(probe);
return;
}
if (bytes >= 4)
{
if (memcmp(probe_recvbuf, "HSUP", 4) == 0)
{
LOG_TRACE("Probed ADC");
if (user_create(probe->hub, probe->connection, &probe->addr))
{
probe->connection = 0;
}
probe_destroy(probe);
return;
}
#ifdef SSL_SUPPORT
if (bytes >= 11 &&
probe_recvbuf[0] == 22 &&
probe_recvbuf[1] == 3 && /* protocol major version */
probe_recvbuf[5] == 1 && /* message type */
probe_recvbuf[9] == probe_recvbuf[1] &&
probe_recvbuf[10] == probe_recvbuf[2])
{
if (probe->hub->config->tls_enable)
{
LOG_TRACE("Probed TLS %d.%d connection", (int) probe_recvbuf[1], (int) probe_recvbuf[2]);
if (user_create(probe->hub, probe->connection, &probe->addr))
{
probe->connection = 0;
}
net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ssl_ctx);
}
else
{
LOG_TRACE("Probed TLS %d.%d connection. TLS disabled in hub.", (int) probe_recvbuf[1], (int) probe_recvbuf[2]);
}
probe_destroy(probe);
return;
}
else
{
LOG_TRACE("Probed TLS %d.%d connection", (int) probe_recvbuf[1], (int) probe_recvbuf[2]);
net_con_ssl_handshake(con, net_con_ssl_mode_server, probe->hub->ssl_ctx);
return;
}
#endif
probe_destroy(probe);
return;
}
}
}
struct hub_probe* probe_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr)
{
struct hub_probe* probe = (struct hub_probe*) hub_malloc_zero(sizeof(struct hub_probe));
if (probe == NULL)
return NULL; /* OOM */
probe->hub = hub;
probe->connection = net_con_create();
net_con_initialize(probe->connection, sd, probe_net_event, probe, NET_EVENT_READ);
net_con_set_timeout(probe->connection, TIMEOUT_CONNECTED);
memcpy(&probe->addr, addr, sizeof(struct ip_addr_encap));
return probe;
}
void probe_destroy(struct hub_probe* probe)
{
if (probe->connection)
{
net_con_close(probe->connection);
probe->connection = 0;
}
hub_free(probe);
}

35
src/core/probe.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_PROBE_H
#define HAVE_UHUB_PROBE_H
#include "uhub.h"
struct hub_probe
{
struct hub_info* hub; /** The hub instance this probe belong to */
struct net_connection* connection; /** Connection data */
struct ip_addr_encap addr; /** IP address */
};
extern struct hub_probe* probe_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr);
extern void probe_destroy(struct hub_probe* probe);
#endif /* HAVE_UHUB_PROBE_H */

View File

@@ -80,11 +80,17 @@ static inline int check_send_queue(struct hub_info* hub, struct hub_user* user,
if (user_flag_get(user, flag_user_list)) if (user_flag_get(user, flag_user_list))
return 1; return 1;
if ((user->net.send_queue->size + msg->length) > get_max_send_queue(hub)) if ((user->send_queue->size + msg->length) > get_max_send_queue(hub))
{
LOG_WARN("send queue overflowed, message discarded.");
return -1; return -1;
}
if (user->net.send_queue->size > get_max_send_queue_soft(hub) && msg->priority < 0) if (user->send_queue->size > get_max_send_queue_soft(hub))
{
LOG_WARN("send queue soft overflowed.");
return 0; return 0;
}
return 1; return 1;
} }
@@ -97,17 +103,20 @@ int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_messag
free(data); free(data);
#endif #endif
if (hub_sendq_is_empty(user->net.send_queue) && !user_flag_get(user, flag_pipeline)) if (!user->connection)
return 0;
if (hub_sendq_is_empty(user->send_queue) && !user_flag_get(user, flag_pipeline))
{ {
/* Perform oportunistic write */ /* Perform oportunistic write */
hub_sendq_add(user->net.send_queue, msg); hub_sendq_add(user->send_queue, msg);
handle_net_write(user); handle_net_write(user);
} }
else else
{ {
if (check_send_queue(hub, user, msg) >= 0) if (check_send_queue(hub, user, msg) >= 0)
{ {
hub_sendq_add(user->net.send_queue, msg); hub_sendq_add(user->send_queue, msg);
if (!user_flag_get(user, flag_pipeline)) if (!user_flag_get(user, flag_pipeline))
user_net_io_want_write(user); user_net_io_want_write(user);
} }
@@ -117,7 +126,7 @@ int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_messag
int route_flush_pipeline(struct hub_info* hub, struct hub_user* u) int route_flush_pipeline(struct hub_info* hub, struct hub_user* u)
{ {
if (hub_sendq_is_empty(u->net.send_queue)) if (hub_sendq_is_empty(u->send_queue))
return 0; return 0;
handle_net_write(u); handle_net_write(u);
@@ -197,7 +206,7 @@ int route_info_message(struct hub_info* hub, struct hub_user* u)
else else
{ {
struct adc_message* cmd = adc_msg_copy(u->info); struct adc_message* cmd = adc_msg_copy(u->info);
const char* address = ip_convert_to_string(&u->net.ipaddr); const char* address = user_get_address(u);
struct hub_user* user = 0; struct hub_user* user = 0;
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR); adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);

View File

@@ -35,28 +35,24 @@ static const char* user_log_str(struct hub_user* user)
} }
#endif #endif
struct hub_user* user_create(struct hub_info* hub, int sd) struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr)
{ {
struct hub_user* user = NULL; struct hub_user* user = NULL;
LOG_TRACE("user_create(), hub=%p, sd=%d", hub, sd); LOG_TRACE("user_create(), hub=%p, con[sd=%d]", hub, net_con_get_sd(con));
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user)); user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL) if (user == NULL)
return NULL; /* OOM */ return NULL; /* OOM */
user->net.tm_connected = time(NULL); user->send_queue = hub_sendq_create();
user->net.send_queue = hub_sendq_create(); user->recv_queue = hub_recvq_create();
user->net.recv_queue = hub_recvq_create();
net_con_initialize(&user->net.connection, sd, user, EV_READ); user->connection = con;
net_con_reinitialize(user->connection, net_event, user, NET_EVENT_READ);
evtimer_set(&user->net.timeout, net_event, user);
event_base_set(hub->evbase, &user->net.timeout);
user_set_timeout(user, TIMEOUT_CONNECTED);
memcpy(&user->id.addr, addr, sizeof(struct ip_addr_encap));
user_set_state(user, state_protocol); user_set_state(user, state_protocol);
return user; return user;
} }
@@ -66,11 +62,8 @@ void user_destroy(struct hub_user* user)
{ {
LOG_TRACE("user_destroy(), user=%p", user); LOG_TRACE("user_destroy(), user=%p", user);
net_con_close(&user->net.connection); hub_recvq_destroy(user->recv_queue);
evtimer_del(&user->net.timeout); hub_sendq_destroy(user->send_queue);
hub_recvq_destroy(user->net.recv_queue);
hub_sendq_destroy(user->net.send_queue);
adc_msg_free(user->info); adc_msg_free(user->info);
user_clear_feature_cast_support(user); user_clear_feature_cast_support(user);
@@ -140,33 +133,36 @@ static int convert_support_fourcc(int fourcc)
#endif #endif
case FOURCC('B','A','S','E'): case FOURCC('B','A','S','E'):
return feature_base; return feature_base;
case FOURCC('A','U','T','0'): case FOURCC('A','U','T','0'):
return feature_auto; return feature_auto;
case FOURCC('U','C','M','0'): case FOURCC('U','C','M','0'):
case FOURCC('U','C','M','D'): case FOURCC('U','C','M','D'):
return feature_ucmd; return feature_ucmd;
case FOURCC('Z','L','I','F'): case FOURCC('Z','L','I','F'):
return feature_zlif; return feature_zlif;
case FOURCC('B','B','S','0'): case FOURCC('B','B','S','0'):
return feature_bbs; return feature_bbs;
case FOURCC('T','I','G','R'): case FOURCC('T','I','G','R'):
return feature_tiger; return feature_tiger;
case FOURCC('B','L','O','M'): case FOURCC('B','L','O','M'):
case FOURCC('B','L','O','0'): case FOURCC('B','L','O','0'):
return feature_bloom; return feature_bloom;
case FOURCC('P','I','N','G'): case FOURCC('P','I','N','G'):
return feature_ping; return feature_ping;
case FOURCC('L','I','N','K'): case FOURCC('L','I','N','K'):
return feature_link; return feature_link;
case FOURCC('A','D','C','S'):
return feature_adcs;
default: default:
LOG_DEBUG("Unknown extension: %x", fourcc); LOG_DEBUG("Unknown extension: %x", fourcc);
return 0; return 0;
@@ -318,37 +314,12 @@ int user_is_registered(struct hub_user* user)
void user_net_io_want_write(struct hub_user* user) void user_net_io_want_write(struct hub_user* user)
{ {
#ifdef DEBUG_SENDQ net_con_update(user->connection, NET_EVENT_READ | NET_EVENT_WRITE);
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) void user_net_io_want_read(struct hub_user* user)
{ {
#ifdef DEBUG_SENDQ net_con_update(user->connection, NET_EVENT_READ);
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) const char* user_get_quit_reason_string(enum user_quit_reason reason)
@@ -372,4 +343,7 @@ const char* user_get_quit_reason_string(enum user_quit_reason reason)
return "unknown"; return "unknown";
} }
const char* user_get_address(struct hub_user* user)
{
return ip_convert_to_string(&user->id.addr);
}

View File

@@ -44,6 +44,7 @@ enum user_flags
feature_bloom = 0x00000040, /** BLO0: Bloom filter (not supported) */ feature_bloom = 0x00000040, /** BLO0: Bloom filter (not supported) */
feature_ping = 0x00000080, /** PING: Hub pinger information extension */ feature_ping = 0x00000080, /** PING: Hub pinger information extension */
feature_link = 0x00000100, /** LINK: Hub link (not supported) */ feature_link = 0x00000100, /** LINK: Hub link (not supported) */
feature_adcs = 0x00000200, /** ADCS: ADC over TLS/SSL */
flag_ignore = 0x01000000, /** Ignore further reads */ flag_ignore = 0x01000000, /** Ignore further reads */
flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */ flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */
flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */ flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */
@@ -78,6 +79,7 @@ struct hub_user_info
sid_t sid; /** session ID */ sid_t sid; /** session ID */
char cid[MAX_CID_LEN+1]; /** global client ID */ char cid[MAX_CID_LEN+1]; /** global client ID */
char nick[MAX_NICK_LEN+1]; /** User's nick name */ char nick[MAX_NICK_LEN+1]; /** User's nick name */
struct ip_addr_encap addr; /** User's IP address */
}; };
/** /**
@@ -87,40 +89,30 @@ struct hub_user_info
*/ */
struct hub_user_limits struct hub_user_limits
{ {
uint64_t shared_size; /** Shared size in bytes */ uint64_t shared_size; /** Shared size in bytes */
size_t shared_files; /** The number of shared files */ size_t shared_files; /** The number of shared files */
size_t upload_slots; /** The number of upload slots */ size_t upload_slots; /** The number of upload slots */
size_t hub_count_user; /** The number of hubs connected as user */ size_t hub_count_user; /** The number of hubs connected as user */
size_t hub_count_registered; /** The number of hubs connected as registered user */ size_t hub_count_registered; /** The number of hubs connected as registered user */
size_t hub_count_operator; /** The number of hubs connected as operator */ size_t hub_count_operator; /** The number of hubs connected as operator */
size_t hub_count_total; /** The number of hubs connected to in total */ size_t hub_count_total; /** The number of hubs connected to in total */
};
struct hub_user_net_io
{
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
{ {
struct hub_user_net_io net; /** Network information data */ enum user_state state; /** see enum user_state */
enum user_state state; /** see enum user_state */ enum user_credentials credentials; /** see enum user_credentials */
enum user_credentials credentials; /** see enum user_credentials */ struct hub_user_info id; /** Contains nick name and CID */
struct hub_user_info id; /** Contains nick name and CID */ uint32_t flags; /** see enum user_features */
int flags; /** see enum user_features */ char user_agent[MAX_UA_LEN+1];/** User agent string */
char user_agent[MAX_UA_LEN+1];/** User agent string */ struct linked_list* feature_cast; /** Features supported by feature cast */
struct linked_list* feature_cast; /** Features supported by feature cast */ struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */
struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */ struct hub_info* hub; /** The hub instance this user belong to */
struct hub_info* hub; /** The hub instance this user belong to */ struct hub_recvq* recv_queue;
struct hub_user_limits limits; /** Data used for limitation */ struct hub_sendq* send_queue;
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */ struct net_connection* connection; /** Connection data */
struct hub_user_limits limits; /** Data used for limitation */
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */
}; };
@@ -135,7 +127,7 @@ struct hub_user
* @param sd socket descriptor associated with the user * @param sd socket descriptor associated with the user
* @return User object or NULL if not enough memory is available. * @return User object or NULL if not enough memory is available.
*/ */
extern struct hub_user* user_create(struct hub_info* hub, int sd); extern struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr);
/** /**
* Delete a user. * Delete a user.
@@ -217,6 +209,8 @@ extern void user_support_add(struct hub_user* user, int fourcc);
*/ */
extern void user_support_remove(struct hub_user* user, int fourcc); extern void user_support_remove(struct hub_user* user, int fourcc);
extern const char* user_get_address(struct hub_user* user);
/** /**
* Sets the nat override flag for a user, this allows users on the same * 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 * subnet as a natted hub to spoof their IP in order to use active mode
@@ -269,24 +263,6 @@ extern void user_net_io_want_write(struct hub_user* user);
*/ */
extern void user_net_io_want_read(struct hub_user* user); 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);
#endif /* HAVE_UHUB_USER_H */ #endif /* HAVE_UHUB_USER_H */

View File

@@ -61,7 +61,7 @@ void uman_update_stats(struct hub_info* hub)
void uman_print_stats(struct hub_info* hub) void uman_print_stats(struct hub_info* hub)
{ {
LOG_INFO("Statistics users=%zu (peak_users=%zu), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)", LOG_INFO("Statistics users=" PRINTF_SIZE_T " (peak_users=" PRINTF_SIZE_T "), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
hub->users->count, hub->users->count,
hub->users->count_peak, hub->users->count_peak,
(int) hub->stats.net_tx / 1024, (int) hub->stats.net_tx / 1024,
@@ -71,23 +71,26 @@ void uman_print_stats(struct hub_info* hub)
} }
#ifdef USERMANAGER_TIMER #ifdef USERMANAGER_TIMER
#ifdef USE_LIBEVENT
static void timer_statistics(int fd, short ev, void *arg) static void timer_statistics(int fd, short ev, void *arg)
{ {
struct hub_info* hub = (struct hub_info*) arg; struct hub_info* hub = (struct hub_info*) arg;
struct timeval timeout = { TIMEOUT_STATS, 0 }; struct timeval timeout = { TIMEOUT_STATS, 0 };
uman_update_stats(hub); uman_update_stats(hub);
evtimer_set(&hub->ev_timer, timer_statistics, hub); evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout); evtimer_add(&hub->ev_timer, &timeout);
} }
#endif #endif
#endif
int uman_init(struct hub_info* hub) int uman_init(struct hub_info* hub)
{ {
struct hub_user_manager* users = NULL; struct hub_user_manager* users = NULL;
#ifdef USERMANAGER_TIMER #ifdef USERMANAGER_TIMER
#ifdef USE_LIBEVENT
struct timeval timeout = { TIMEOUT_STATS, 0 }; struct timeval timeout = { TIMEOUT_STATS, 0 };
#endif
#endif #endif
if (!hub) if (!hub)
return -1; return -1;
@@ -102,18 +105,20 @@ int uman_init(struct hub_info* hub)
if (!users->list) if (!users->list)
{ {
list_destroy(users->list); list_destroy(users->list);
hub_free(users);
return -1; return -1;
} }
hub->users = users; hub->users = users;
#ifdef USERMANAGER_TIMER #ifdef USERMANAGER_TIMER
if (hub->evbase) #ifdef USE_LIBEVENT
if (net_get_evbase())
{ {
evtimer_set(&hub->ev_timer, timer_statistics, hub); evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout); evtimer_add(&hub->ev_timer, &timeout);
} }
#endif
#endif // 0 #endif // 0
return 0; return 0;
} }
@@ -125,8 +130,10 @@ int uman_shutdown(struct hub_info* hub)
return -1; return -1;
#ifdef USERMANAGER_TIMER #ifdef USERMANAGER_TIMER
#ifdef USE_LIBEVENT
if (evtimer_pending(&hub->ev_timer, 0)) if (evtimer_pending(&hub->ev_timer, 0))
event_del(&hub->ev_timer); evtimer_del(&hub->ev_timer);
#endif
#endif #endif
if (hub->users->list) if (hub->users->list)
@@ -223,7 +230,7 @@ size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, st
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */ struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user) while (user)
{ {
if (ip_in_range(&user->net.ipaddr, range)) if (ip_in_range(&user->id.addr, range))
{ {
list_append(users, user); list_append(users, user);
num++; num++;

View File

@@ -27,7 +27,7 @@ struct hub_user_manager
struct sid_pool* sids; struct sid_pool* sids;
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */ uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */ uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct linked_list* list; /**<< "Contains all users" */ struct linked_list* list; /**<< "Contains all logged in users" */
}; };
/** /**

39
src/network/backend.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_NETWORK_BACKEND_H
#define HAVE_UHUB_NETWORK_BACKEND_H
/**
* Initialize the network backend.
* Returns 1 on success, or 0 on failure.
*/
extern int net_backend_initialize();
/**
* Shutdown the network connection backend.
*/
extern void net_backend_shutdown();
/**
* Process the network backend.
*/
extern int net_backend_process();
#endif /* HAVE_UHUB_NETWORK_BACKEND_H */

37
src/network/common.h Normal file
View File

@@ -0,0 +1,37 @@
#define NET_WANT_READ NET_EVENT_READ
#define NET_WANT_WRITE NET_EVENT_WRITE
#define NET_WANT_ACCEPT 0x0008
#define NET_WANT_SSL_READ 0x0010
#define NET_WANT_SSL_WRITE 0x0020
#define NET_WANT_SSL_ACCEPT 0x0040
#define NET_WANT_SSL_CONNECT 0x0080
#define NET_WANT_SSL_X509_LOOKUP 0x0100
#define NET_PROCESSING_BUSY 0x8000
#define NET_CLEANUP 0x4000
#define NET_INITIALIZED 0x2000
#define NET_TIMER_ENABLED 0x1000
/* FIXME: Meant for debugging */
#define NET_EVENT_SET 0x0800
#define NET_CON_STRUCT_BASIC \
int sd; /** socket descriptor */ \
uint32_t flags; /** Connection flags */ \
void* ptr; /** data pointer */ \
net_connection_cb callback; /** Callback function */ \
#define NET_CON_STRUCT_SSL \
SSL* ssl; /** SSL handle */ \
size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ \
#ifdef USE_SSL
#define NET_CON_STRUCT_COMMON \
NET_CON_STRUCT_BASIC \
NET_CON_STRUCT_SSL
#else
#define NET_CON_STRUCT_COMMON \
NET_CON_STRUCT_BASIC
#endif

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -18,35 +18,193 @@
*/ */
#include "uhub.h" #include "uhub.h"
#include "network/common.h"
extern struct hub_info* g_hub; #ifdef SSL_SUPPORT
static int handle_openssl_error(struct net_connection* con, int ret)
void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events)
{ {
con->sd = sd; uhub_assert(con);
con->ptr = (void*) ptr;
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr); int error = SSL_get_error(net_con_get_ssl(con), ret);
event_base_set(g_hub->evbase, &con->event); switch (error)
event_add(&con->event, 0); {
case SSL_ERROR_ZERO_RETURN:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error);
return -1;
case SSL_ERROR_WANT_READ:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error);
net_con_update(con, NET_EVENT_READ | NET_WANT_SSL_READ);
return 0;
case SSL_ERROR_WANT_WRITE:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_WRITE);
return 0;
case SSL_ERROR_WANT_CONNECT:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_CONNECT", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_CONNECT);
return 0;
case SSL_ERROR_WANT_ACCEPT:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_ACCEPT", ret, error);
net_con_update(con, NET_EVENT_READ | NET_EVENT_WRITE | NET_WANT_SSL_ACCEPT);
return 0;
case SSL_ERROR_WANT_X509_LOOKUP:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_X509_LOOKUP", ret, error);
return 0;
case SSL_ERROR_SYSCALL:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error);
/* if ret == 0, connection closed, if ret == -1, check with errno */
if (ret == 0)
return -1;
else
return -net_error();
case SSL_ERROR_SSL:
LOG_PROTO("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error);
/* internal openssl error */
return -1;
}
return -1;
} }
void net_con_update(struct net_connection* con, int events) ssize_t net_con_ssl_accept(struct net_connection* con)
{ {
if (event_pending(&con->event, EV_READ | EV_WRITE, 0) == events) uhub_assert(con);
return;
event_del(&con->event); ssize_t ret = SSL_accept(net_con_get_ssl(con));
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr); #ifdef NETWORK_DUMP_DEBUG
event_add(&con->event, 0); LOG_PROTO("SSL_accept() ret=%d", ret);
#endif
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
} }
void net_con_close(struct net_connection* con) ssize_t net_con_ssl_connect(struct net_connection* con)
{ {
if (!event_pending(&con->event, EV_READ | EV_WRITE, 0)) uhub_assert(con);
return;
event_del(&con->event); ssize_t ret = SSL_connect(net_con_get_ssl(con));
net_close(con->sd); #ifdef NETWORK_DUMP_DEBUG
con->sd = -1; LOG_PROTO("SSL_connect() ret=%d", ret);
#endif
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
}
else
{
return handle_openssl_error(con, ret);
}
return ret;
} }
ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssl_mode, SSL_CTX* ssl_ctx)
{
uhub_assert(con);
SSL* ssl = 0;
if (ssl_mode == net_con_ssl_mode_server)
{
ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, net_con_get_sd(con));
net_con_set_ssl(con, ssl);
return net_con_ssl_accept(con);
}
else
{
ssl = SSL_new(SSL_CTX_new(TLSv1_method()));
SSL_set_fd(ssl, net_con_get_sd(con));
net_con_set_ssl(con, ssl);
return net_con_ssl_connect(con);
}
}
#endif /* SSL_SUPPORT */
ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len)
{
int ret = net_send(net_con_get_sd(con), buf, len, UHUB_SEND_SIGNAL);
if (ret == -1)
{
if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0;
return -1;
}
return ret;
}
ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
{
uhub_assert(con);
#ifdef SSL_SUPPORT
if (!net_con_is_ssl(con))
{
#endif
int ret = net_recv(net_con_get_sd(con), buf, len, 0);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_recv: ret=%d", ret);
#endif
if (ret == -1)
{
if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0;
return -net_error();
}
else if (ret == 0)
{
return -1;
}
return ret;
#ifdef SSL_SUPPORT
}
else
{
int ret = SSL_read(net_con_get_ssl(con), buf, len);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_recv: ret=%d", ret);
#endif
if (ret > 0)
{
net_con_update(con, NET_EVENT_READ);
}
else
{
return -handle_openssl_error(con, ret);
}
return ret;
}
#endif
}
ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
{
int ret = net_recv(net_con_get_sd(con), buf, len, MSG_PEEK);
if (ret == -1)
{
if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0;
return -net_error();
}
else if (ret == 0)
return -1;
return ret;
}

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,21 +21,90 @@
#define HAVE_UHUB_NETWORK_CONNECTION_H #define HAVE_UHUB_NETWORK_CONNECTION_H
#include "uhub.h" #include "uhub.h"
#include "network/backend.h"
#define NET_EVENT_TIMEOUT 0x0001
#define NET_EVENT_READ 0x0002
#define NET_EVENT_WRITE 0x0004
#define NET_EVENT_SOCKERROR 0x1000 /* Socket error, closed */
#define NET_EVENT_CLOSED 0x2000 /* Socket closed */
struct net_connection;
typedef void (*net_connection_cb)(struct net_connection*, int event, void* ptr);
extern int net_con_get_sd(struct net_connection* con);
extern void* net_con_get_ptr(struct net_connection* con);
extern struct net_connection* net_con_create();
extern void net_con_destroy(struct net_connection*);
extern void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events);
extern void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events);
extern void net_con_update(struct net_connection* con, int events);
/**
* Close the connection.
* This will ensure a connection is closed properly and will generate a NET_EVENT_DESTROYED event which indicates
* that the con can safely be deleted (or set to NULL).
* @returns 1 if the memory pointed to by con can be freed immediately, or 0 if it needs to go through the NET_EVENT_DESTROYED event.
*/
extern int net_con_close(struct net_connection* con);
/**
* Send data
*
* @return returns the number of bytes sent.
* 0 if no data is sent, and this function should be called again (EWOULDBLOCK/EINTR)
* <0 if an error occured, the negative number contains the error code.
*/
extern ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len);
/**
* Receive data
*
* @return returns the number of bytes sent.
* 0 if no data is sent, and this function should be called again (EWOULDBLOCK/EINTR)
* <0 if an error occured, the negative number contains the error code.
*/
extern ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len);
/**
* Receive data without removing them from the recv() buffer.
* NOTE: This does not currently work for SSL connections after the SSL handshake has been
* performed.
*/
extern ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len);
/**
* Set timeout for connetion.
*
* @param seconds the number of seconds into the future.
*/
extern void net_con_set_timeout(struct net_connection* con, int seconds);
extern void net_con_clear_timeout(struct net_connection* con);
struct net_connection
{
int sd; /** socket descriptor */
void* ptr; /** data pointer */
struct event event; /** libevent struct for read/write events */
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
SSL* ssl; /** SSL handle */ /**
#endif /* SSL_SUPPORT */ * Start SSL_accept()
*/
extern ssize_t net_con_ssl_accept(struct net_connection*);
/**
* Start SSL_connect()
*/
extern ssize_t net_con_ssl_connect(struct net_connection*);
enum net_con_ssl_mode
{
net_con_ssl_mode_server,
net_con_ssl_mode_client,
}; };
extern void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events); extern ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode, SSL_CTX* ssl_ctx);
extern void net_con_update(struct net_connection* con, int events);
extern void net_con_close(struct net_connection* con);
extern int net_con_is_ssl(struct net_connection* con);
extern SSL* net_con_get_ssl(struct net_connection* con);
extern void net_con_set_ssl(struct net_connection* con, SSL*);
#endif /* SSL_SUPPORT */
#endif /* HAVE_UHUB_NETWORK_CONNECTION_H */ #endif /* HAVE_UHUB_NETWORK_CONNECTION_H */

306
src/network/epoll.c Normal file
View File

@@ -0,0 +1,306 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef USE_EPOLL
#include "network/connection.h"
#include "network/common.h"
#include "network/backend.h"
#define EPOLL_EVBUFFER 512
struct net_connection
{
int sd;
uint32_t flags;
net_connection_cb callback;
void* ptr;
struct epoll_event ev;
struct timeout_evt* timeout;
#ifdef SSL_SUPPORT
SSL* ssl;
size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */
#endif
};
struct net_backend
{
int epfd;
size_t num;
size_t max;
struct net_connection** conns;
struct epoll_event events[EPOLL_EVBUFFER];
time_t now;
struct timeout_queue timeout_queue;
};
static struct net_backend* g_backend = 0;
static void net_con_print(const char* prefix, struct net_connection* con)
{
char buf[512];
int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, ev={ events=%s%s, data.ptr=%p }",
prefix, con->sd, con->flags, con->callback, con->ptr, (con->ev.events & EPOLLIN ? "R" : ""),(con->ev.events & EPOLLOUT ? "W" : "") , con->ev.data.ptr);
if (con->timeout)
{
sprintf(buf + off, ", timeout={ %d seconds left }", (int) (con->timeout->timestamp - g_backend->now));
}
else
{
sprintf(buf + off, ", timeout=NULL");
}
LOG_TRACE(buf);
}
/**
* Initialize the network backend.
* Returns 1 on success, or 0 on failure.
*/
int net_backend_initialize()
{
size_t max = net_get_max_sockets();
g_backend = hub_malloc(sizeof(struct net_backend));
g_backend->epfd = epoll_create(max);
if (g_backend->epfd == -1)
{
LOG_WARN("Unable to create epoll socket.");
return 0;
}
g_backend->num = 0;
g_backend->max = max;
g_backend->conns = hub_malloc_zero(sizeof(struct net_connection*) * max);
memset(g_backend->events, 0, sizeof(g_backend->events));
g_backend->now = time(0);
timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* look max 10 minutes into the future. */
return 1;
}
/**
* Shutdown the network connection backend.
*/
void net_backend_shutdown()
{
close(g_backend->epfd);
hub_free(g_backend->conns);
hub_free(g_backend);
}
/**
* Process the network backend.
*/
int net_backend_process()
{
int n;
LOG_TRACE("epoll_wait: fd=%d, events=%x, max=%zu", g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER));
int res = epoll_wait(g_backend->epfd, g_backend->events, MIN(g_backend->num, EPOLL_EVBUFFER), 1000);
if (res == -1)
{
LOG_WARN("epoll_wait returned -1");
return 0;
}
for (n = 0; n < res; n++)
{
struct net_connection* con = (struct net_connection*) g_backend->events[n].data.ptr;
int ev = 0;
if (g_backend->events[n].events & EPOLLIN) ev |= NET_EVENT_READ;
if (g_backend->events[n].events & EPOLLOUT) ev |= NET_EVENT_WRITE;
con->callback(con, ev, con->ptr);
}
return 1;
}
struct net_connection* net_con_create()
{
struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection));
con->sd = -1;
return con;
}
void net_con_destroy(struct net_connection* con)
{
hub_free(con);
}
void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events)
{
con->sd = sd;
con->flags = NET_INITIALIZED;
con->callback = callback;
con->ev.events = 0;
con->ptr = (void*) ptr;
con->ev.data.ptr = (void*) con;
net_set_nonblocking(con->sd, 1);
net_set_nosigpipe(con->sd, 1);
if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN;
if (events & NET_EVENT_WRITE) con->ev.events |= EPOLLOUT;
g_backend->conns[sd] = con;
g_backend->num++;
if (epoll_ctl(g_backend->epfd, EPOLL_CTL_ADD, con->sd, &con->ev) == -1)
{
LOG_TRACE("epoll_ctl() add failed.");
}
net_con_print("ADD", con);
}
void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events)
{
con->callback = callback;
con->ptr = (void*) ptr;
net_con_update(con, events);
}
void net_con_update(struct net_connection* con, int events)
{
con->ev.events = 0;
if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN;
if (events & NET_EVENT_WRITE) con->ev.events |= EPOLLOUT;
#ifdef SSL_SUPPORT
if (events & NET_WANT_SSL_WRITE)
con->flags |= NET_WANT_SSL_WRITE;
else
con->flags &= ~NET_WANT_SSL_WRITE;
if (events & NET_WANT_SSL_READ)
con->flags |= NET_WANT_SSL_READ;
else
con->flags &= ~NET_WANT_SSL_READ;
if (events & NET_WANT_SSL_ACCEPT)
con->flags |= NET_WANT_SSL_ACCEPT;
else
con->flags &= ~NET_WANT_SSL_ACCEPT;
if (events & NET_WANT_SSL_CONNECT)
con->flags |= NET_WANT_SSL_CONNECT;
else
con->flags &= ~NET_WANT_SSL_CONNECT;
#endif /* SSL_SUPPORT */
if (epoll_ctl(g_backend->epfd, EPOLL_CTL_MOD, con->sd, &con->ev) == -1)
{
LOG_TRACE("epoll_ctl() modify failed.");
}
net_con_print("MOD", con);
}
int net_con_close(struct net_connection* con)
{
if (!(con->flags & NET_INITIALIZED))
return 0;
con->flags &= ~NET_INITIALIZED;
if (con->sd != -1)
{
g_backend->conns[con->sd] = 0;
g_backend->num--;
}
if (timeout_evt_is_scheduled(con->timeout))
{
timeout_queue_remove(&g_backend->timeout_queue, con->timeout);
hub_free(con->timeout);
con->timeout = 0;
}
if (epoll_ctl(g_backend->epfd, EPOLL_CTL_DEL, con->sd, &con->ev) == -1)
{
LOG_WARN("epoll_ctl() delete failed.");
}
net_con_print("DEL", con);
return 0;
}
#ifdef SSL_SUPPORT
int net_con_is_ssl(struct net_connection* con)
{
return con->ssl != 0;
}
SSL* net_con_get_ssl(struct net_connection* con)
{
return con->ssl;
}
void net_con_set_ssl(struct net_connection* con, SSL* ssl)
{
con->ssl = ssl;
}
#endif
int net_con_get_sd(struct net_connection* con)
{
return con->sd;
}
void* net_con_get_ptr(struct net_connection* con)
{
return con->ptr;
}
void timeout_evt_initialize(struct timeout_evt*, timeout_evt_cb, void* ptr);
void timeout_evt_reset(struct timeout_evt*);
int timeout_evt_is_scheduled(struct timeout_evt*);
static void timeout_callback(struct timeout_evt* evt)
{
struct net_connection* con = (struct net_connection*) evt->ptr;
con->callback(con, NET_EVENT_TIMEOUT, con->ptr);
}
void net_con_set_timeout(struct net_connection* con, int seconds)
{
if (!con->timeout)
{
con->timeout = hub_malloc_zero(sizeof(struct timeout_evt));
timeout_evt_initialize(con->timeout, timeout_callback, con);
timeout_queue_insert(&g_backend->timeout_queue, con->timeout, seconds);
}
else
{
timeout_queue_reschedule(&g_backend->timeout_queue, con->timeout, seconds);
}
}
void net_con_clear_timeout(struct net_connection* con)
{
if (con->timeout && timeout_evt_is_scheduled(con->timeout))
{
timeout_queue_remove(&g_backend->timeout_queue, con->timeout);
hub_free(con->timeout);
con->timeout = 0;
}
}
#endif /* USE_EPOLL */

399
src/network/libevent.c Normal file
View File

@@ -0,0 +1,399 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef USE_LIBEVENT
struct net_connection
{
NET_CON_STRUCT_COMMON
struct event event; /** libevent struct for read/write events */
struct event timeout; /** Used for internal timeout handling */
};
struct net_timer
{
unsigned int initialized;
struct event timeout;
net_timeout_cb callback;
void* ptr;
};
int net_con_get_sd(struct net_connection* con)
{
return con->sd;
}
void* net_con_get_ptr(struct net_connection* con)
{
return con->ptr;
}
struct net_connection* net_con_create()
{
struct net_connection* con = (struct net_connection*) hub_malloc(sizeof(struct net_connection));
return con;
}
static inline int net_con_flag_get(struct net_connection* con, unsigned int flag)
{
return con->flags & flag;
}
static inline void net_con_flag_set(struct net_connection* con, unsigned int flag)
{
con->flags |= flag;
}
static inline void net_con_flag_unset(struct net_connection* con, unsigned int flag)
{
con->flags &= ~flag;
}
void net_con_destroy(struct net_connection* con)
{
hub_free(con);
}
static inline int net_con_convert_to_libevent_mask(int ev)
{
int events = 0;
if (ev & NET_EVENT_READ) events |= EV_READ;
if (ev & NET_EVENT_WRITE) events |= EV_WRITE;
return events;
}
static inline int net_con_convert_from_libevent_mask(int ev)
{
int events = 0;
if (ev & EV_TIMEOUT) events |= NET_EVENT_TIMEOUT;
if (ev & EV_READ) events |= NET_EVENT_READ;
if (ev & EV_WRITE) events |= NET_EVENT_WRITE;
return events;
}
static void net_con_event(int fd, short ev, void *arg);
int net_con_close(struct net_connection* con)
{
uhub_assert(con);
con->ptr = 0;
if (net_con_flag_get(con, NET_CLEANUP))
return 0;
if (net_con_flag_get(con, NET_PROCESSING_BUSY))
{
net_con_flag_set(con, NET_CLEANUP);
return 0;
}
net_con_after_close(con);
return 1;
}
static void net_con_set(struct net_connection* con)
{
uhub_assert(con);
int ev = 0;
if (net_con_flag_get(con, NET_WANT_READ | NET_WANT_SSL_READ)) ev |= EV_READ;
if (net_con_flag_get(con, NET_WANT_WRITE | NET_WANT_SSL_WRITE)) ev |= EV_WRITE;
if (net_con_flag_get(con, NET_EVENT_SET) != 0)
{
event_del(&con->event);
}
net_con_flag_set(con, NET_EVENT_SET);
LOG_MEMORY("SET: set+add: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev);
event_set(&con->event, con->sd, ev, net_con_event, con);
event_add(&con->event, 0);
net_con_flag_set(con, NET_INITIALIZED);
}
static void net_con_after_close(struct net_connection* con)
{
if (net_con_flag_get(con, NET_INITIALIZED))
{
LOG_MEMORY("DEL: close: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, -1);
net_con_flag_unset(con, NET_EVENT_SET);
event_del(&con->event);
net_con_flag_unset(con, NET_INITIALIZED);
}
net_con_clear_timeout(con);
net_close(con->sd);
con->sd = -1;
hub_free(con);
}
void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int ev)
{
uhub_assert(con);
int events = net_con_convert_to_libevent_mask(ev);
if (ev & NET_EVENT_READ) net_con_flag_set(con, NET_WANT_READ);
if (ev & NET_EVENT_WRITE) net_con_flag_set(con, NET_WANT_WRITE);
con->sd = sd;
con->flags = 0;
con->ptr = (void*) ptr;
con->callback = callback;
con->last_send = time(0);
con->last_recv = con->last_send;
if (ev)
{
uhub_assert(net_con_flag_get(con, NET_EVENT_SET) == 0);
net_con_flag_set(con, NET_EVENT_SET);
LOG_MEMORY("SET: init: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev);
event_set(&con->event, con->sd, events, net_con_event, con);
event_add(&con->event, 0);
net_con_flag_set(con, NET_INITIALIZED);
}
net_set_nonblocking(sd, 1);
net_set_nosigpipe(sd, 1);
#ifdef SSL_SUPPORT
con->ssl = NULL;
con->write_len = 0;
#endif
}
void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events)
{
uhub_assert(con);
con->callback = callback;
con->ptr = (void*) ptr;
net_con_update(con, events);
}
void net_con_update(struct net_connection* con, int ev)
{
uhub_assert(con);
if (ev & NET_EVENT_READ)
net_con_flag_set(con, NET_EVENT_READ);
else
net_con_flag_unset(con, NET_EVENT_READ);
if (ev & NET_EVENT_WRITE)
net_con_flag_set(con, NET_EVENT_WRITE);
else
net_con_flag_unset(con, NET_EVENT_WRITE);
if (!net_con_flag_get(con, NET_PROCESSING_BUSY))
{
net_con_set(con);
}
}
#define CALLBACK(CON, EVENTS) \
if (CON->callback) \
CON->callback(con, EVENTS, CON->ptr);
static void net_con_event(int fd, short ev, void *arg)
{
struct net_connection* con = (struct net_connection*) arg;
int events = net_con_convert_from_libevent_mask(ev);
if (!net_con_flag_get(con, NET_INITIALIZED))
{
return;
}
if (net_con_flag_get(con, NET_CLEANUP))
{
net_con_after_close(con);
return;
}
net_con_flag_set(con, NET_PROCESSING_BUSY);
// uhub_assert(net_con_flag_get(con, NET_EVENT_SET) != 0);
net_con_flag_unset(con, NET_EVENT_SET);
LOG_MEMORY("EVT: process: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, (int) ev);
#ifdef SSL_SUPPORT
if (!con->ssl)
{
#endif
CALLBACK(con, events);
#ifdef SSL_SUPPORT
}
else
{
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_con_event: events=%d, con=%p", ev, con);
#endif
if (ev & (EV_READ | EV_WRITE))
{
if (net_con_flag_get(con, NET_WANT_SSL_ACCEPT))
{
if (net_con_ssl_accept(con) < 0)
CALLBACK(con, NET_EVENT_SOCKERROR);
}
else if (net_con_flag_get(con, NET_WANT_SSL_CONNECT))
{
if (net_con_ssl_connect(con) < 0)
CALLBACK(con, NET_EVENT_SOCKERROR);
}
else if (ev == EV_READ && net_con_flag_get(con, NET_WANT_SSL_READ))
{
CALLBACK(con, NET_EVENT_WRITE);
}
else if (ev == EV_WRITE && net_con_flag_get(con, NET_WANT_SSL_WRITE))
{
CALLBACK(con, events & NET_EVENT_READ);
}
else
{
CALLBACK(con, events);
}
}
else
{
CALLBACK(con, events);
}
}
#endif
net_con_flag_unset(con, NET_PROCESSING_BUSY);
if (net_con_flag_get(con, NET_CLEANUP))
{
net_con_after_close(con);
}
else
{
net_con_set(con);
}
}
static void net_timer_event(int fd, short ev, void *arg)
{
struct net_timer* timer = (struct net_timer*) arg;
timer->callback(timer, timer->ptr);
}
void net_timer_initialize(struct net_timer* timer, net_timeout_cb callback, void* ptr)
{
timer->initialized = 0;
timer->callback = callback;
timer->ptr = ptr;
}
void net_timer_reset(struct net_timer* timer, int seconds)
{
struct timeval timeout = { seconds, 0 };
if (timer->initialized)
{
evtimer_del(&timer->timeout);
timer->initialized = 0;
}
evtimer_set(&timer->timeout, net_timer_event, timer);
evtimer_add(&timer->timeout, &timeout);
}
void net_timer_shutdown(struct net_timer* timer)
{
if (timer->initialized)
{
evtimer_del(&timer->timeout);
timer->initialized = 0;
}
timer->callback = 0;
timer->ptr = 0;
}
void net_con_set_timeout(struct net_connection* con, int seconds)
{
uhub_assert(con);
struct timeval timeout = { seconds, 0 };
net_con_clear_timeout(con);
evtimer_set(&con->timeout, net_con_event, con);
evtimer_add(&con->timeout, &timeout);
net_con_flag_set(con, NET_TIMER_ENABLED);
}
void net_con_clear_timeout(struct net_connection* con)
{
uhub_assert(con);
if (net_con_flag_get(con, NET_TIMER_ENABLED))
{
evtimer_del(&con->timeout);
net_con_flag_unset(con, NET_TIMER_ENABLED);
}
}
static struct event_base g_evbase = 0;
/**
* Initialize the network backend.
* Returns 1 on success, or 0 on failure.
*/
int net_backend_initialize()
{
g_evbase = event_init();
if (!g_evbase)
{
LOG_ERROR("Unable to initialize libevent.");
return 0;
}
LOG_DEBUG("Using libevent %s, backend: %s", event_get_version(), event_get_method());
return 1;
}
/**
* Shutdown the network connection backend.
*/
void net_backend_shutdown()
{
event_base_free(g_evbase);
}
/**
* Process the network backend.
*/
int net_backend_process()
{
int ret = event_base_loop(g_evbase, EVLOOP_ONCE);
if (ret != 0)
{
LOG_DEBUG("event_base_loop returned: %d", (int) ret);
}
if (ret < 0)
return 0;
return 1;
}
#endif /* USE_LIBEVENT */

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
static int is_ipv6_supported = -1; /* -1 = CHECK, 0 = NO, 1 = YES */ static int is_ipv6_supported = -1; /* -1 = CHECK, 0 = NO, 1 = YES */
static int net_initialized = 0; static int net_initialized = 0;
static struct net_statistics stats; static struct net_statistics stats;
static struct net_statistics stats_total; static struct net_statistics stats_total;
@@ -35,6 +36,7 @@ int net_initialize()
{ {
if (!net_initialized) if (!net_initialized)
{ {
LOG_TRACE("Initializing network monitor.");
#ifdef WINSOCK #ifdef WINSOCK
struct WSAData wsa; struct WSAData wsa;
@@ -45,13 +47,13 @@ int net_initialize()
} }
#endif /* WINSOCK */ #endif /* WINSOCK */
LOG_TRACE("Initializing network monitor."); net_backend_initialize();
net_stats_initialize(); net_stats_initialize();
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
LOG_TRACE("Initializing OpenSSL..."); LOG_TRACE("Initializing OpenSSL...");
SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
#endif /* SSL_SUPPORT */ #endif /* SSL_SUPPORT */
@@ -70,10 +72,16 @@ size_t net_get_max_sockets()
return limits.rlim_max; return limits.rlim_max;
} }
LOG_ERROR("getrlimit() failed"); LOG_ERROR("getrlimit() failed");
#else
LOG_ERROR("System does not have getrlimit(): constrained to 1024 sockets");
#endif /* HAVE_GETRLIMIT */
return 1024; return 1024;
#else
#ifdef WIN32
LOG_WARN("Windows system, limited to 4096 connections.");
return 4096;
#else
LOG_WARN("System does not have getrlimit(): constrained to 1024 sockets");
return 1024;
#endif
#endif /* HAVE_GETRLIMIT */
} }
@@ -83,6 +91,8 @@ int net_destroy()
{ {
LOG_TRACE("Shutting down network monitor"); LOG_TRACE("Shutting down network monitor");
net_backend_shutdown();
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
/* FIXME: Shutdown OpenSSL here. */ /* FIXME: Shutdown OpenSSL here. */
#endif #endif
@@ -96,6 +106,13 @@ int net_destroy()
return -1; return -1;
} }
#ifdef USE_LIBEVENT
struct event_base* net_get_evbase()
{
return net_evbase;
}
#endif
static void net_error_out(int fd, const char* func) static void net_error_out(int fd, const char* func)
{ {
int err = net_error(); int err = net_error();
@@ -165,8 +182,18 @@ int net_set_nonblocking(int fd, int toggle)
#ifdef WINSOCK #ifdef WINSOCK
u_long on = toggle ? 1 : 0; u_long on = toggle ? 1 : 0;
ret = ioctlsocket(fd, FIONBIO, &on); ret = ioctlsocket(fd, FIONBIO, &on);
#else
#ifdef __sun__
int flags = fcntl(fd, F_GETFL, 0);
if (flags != -1)
{
if (toggle) flags |= O_NONBLOCK;
else flags &= ~O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
}
#else #else
ret = ioctl(fd, FIONBIO, &toggle); ret = ioctl(fd, FIONBIO, &toggle);
#endif
#endif #endif
if (ret == -1) if (ret == -1)
{ {
@@ -270,7 +297,7 @@ int net_close(int fd)
} }
else else
{ {
if (fd != -1) if (ret != -1)
{ {
net_stats_add_error(); net_stats_add_error();
} }
@@ -441,6 +468,7 @@ int net_socket_create(int af, int type, int protocol)
if (sd == -1) if (sd == -1)
{ {
net_error_out(sd, "net_socket_create"); net_error_out(sd, "net_socket_create");
return -1;
} }
#ifdef SOCK_DUAL_STACK_OPT #ifdef SOCK_DUAL_STACK_OPT

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -32,15 +32,6 @@ struct net_statistics
struct net_socket_t; 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. * Initialize the socket monitor subsystem.
* On some operating systems this will also involve loading the TCP/IP stack * On some operating systems this will also involve loading the TCP/IP stack
@@ -60,6 +51,8 @@ extern int net_initialize();
*/ */
extern int net_destroy(); extern int net_destroy();
extern struct event_base* net_get_evbase();
/** /**
* @return the number of sockets currrently being monitored. * @return the number of sockets currrently being monitored.
*/ */

137
src/system.h Normal file
View 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/>.
*
*/
#ifndef HAVE_UHUB_SYSTEM_H
#define HAVE_UHUB_SYSTEM_H
#define _FILE_OFFSET_BITS 64
#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
#endif
#if defined(__CYGWIN__) || defined(__MINGW32__)
#ifndef WINSOCK
#define WINSOCK
#endif
#endif
#ifdef WINSOCK
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#if !defined(WIN32)
#include <grp.h>
#include <pwd.h>
#include <sys/resource.h>
#define HAVE_STRNDUP
#define HAVE_MEMMEM
#define HAVE_GETRLIMIT
#endif
/* printf and size_t support */
#if defined(WIN32)
/* Windows uses %Iu for size_t */
#define PRINTF_SIZE_T "%Iu"
#else
#define PRINTF_SIZE_T "%zu"
#endif
#ifdef SSL_SUPPORT
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
#include "../version.h"
#define uhub_assert assert
#ifdef USE_LIBEVENT
#include <event.h>
#else
#ifdef __linux__
#define USE_EPOLL
#include <sys/epoll.h>
#endif
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__)
#undef HAVE_STRNDUP
#undef HAVE_MEMMEM
#endif
#ifdef MSG_NOSIGNAL
#define UHUB_SEND_SIGNAL MSG_NOSIGNAL
#else
#ifdef MSG_NOPIPE
#define UHUB_SEND_SIGNAL MSG_NOPIPE
#else
#define UHUB_SEND_SIGNAL 0
#endif
#endif
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif /* HAVE_UHUB_SYSTEM_H */

491
src/tools/adcclient.c Normal file
View File

@@ -0,0 +1,491 @@
/*
* 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 "tools/adcclient.h"
#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR ADPING\n"
#define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768
#define TIGERSIZE 24
static ssize_t ADC_client_recv(struct ADC_client* client);
static void ADC_client_send_info(struct ADC_client* client);
static void ADC_client_on_connected(struct ADC_client* client);
static void ADC_client_on_disconnected(struct ADC_client* client);
static void ADC_client_on_login(struct ADC_client* client);
static int ADC_client_parse_address(struct ADC_client* client, const char* arg);
static void ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length);
static void ADC_client_debug(struct ADC_client* client, const char* format, ...)
{
char logmsg[1024];
va_list args;
va_start(args, format);
vsnprintf(logmsg, 1024, format, args);
va_end(args);
fprintf(stdout, "* [%p] %s\n", client, logmsg);
}
static void ADC_client_set_state(struct ADC_client* client, enum ADC_client_state state)
{
client->state = state;
}
static void adc_cid_pid(struct ADC_client* client)
{
char seed[64];
char pid[64];
char cid[64];
uint64_t tiger_res1[3];
uint64_t tiger_res2[3];
/* create cid+pid pair */
memset(seed, 0, 64);
snprintf(seed, 64, VERSION "%p", client);
tiger((uint64_t*) seed, strlen(seed), tiger_res1);
base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
cid[ADC_CID_SIZE] = 0;
pid[ADC_CID_SIZE] = 0;
adc_msg_add_named_argument(client->info, ADC_INF_FLAG_PRIVATE_ID, pid);
adc_msg_add_named_argument(client->info, ADC_INF_FLAG_CLIENT_ID, cid);
}
static void event_callback(struct net_connection* con, int events, void *arg)
{
struct ADC_client* client = (struct ADC_client*) net_con_get_ptr(con);
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED)
{
printf("NET_EVENT_SOCKERROR || NET_EVENT_CLOSED\n");
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
return;
}
if (events == NET_EVENT_TIMEOUT)
{
if (client->state == ps_conn)
{
client->callback(client, ADC_CLIENT_DISCONNECTED, 0);
}
}
if (events & NET_EVENT_READ)
{
if (ADC_client_recv(client) == -1)
{
ADC_client_on_disconnected(client);
}
}
if (events & NET_EVENT_WRITE)
{
if (client->state == ps_conn)
{
ADC_client_connect(client, 0);
}
else
{
/* FIXME: Call send again */
}
}
}
#define UNESCAPE_ARG(TMP, TARGET) \
if (TMP) \
TARGET = adc_msg_unescape(TMP); \
else \
TARGET = NULL; \
hub_free(TMP);
#define EXTRACT_NAMED_ARG(MSG, NAME, TARGET) \
do { \
char* tmp = adc_msg_get_named_argument(MSG, NAME); \
UNESCAPE_ARG(tmp, TARGET); \
} while (0)
#define EXTRACT_POS_ARG(MSG, POS, TARGET) \
do { \
char* tmp = adc_msg_get_argument(MSG, POS); \
UNESCAPE_ARG(tmp, TARGET); \
} while (0)
static void ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length)
{
#ifdef ADC_CLIENT_DEBUG_PROTO
ADC_client_debug(client, "- LINE: '%s'", start);
#endif
/* Parse message */
struct adc_message* msg = adc_msg_parse(line, length);
if (!msg)
{
ADC_client_debug(client, "WARNING: Message cannot be decoded: \"%s\"", line);
return;
}
if (length < 4)
{
ADC_client_debug(client, "Unexpected response from hub: '%s'", line);
return;
}
switch (msg->cmd)
{
case ADC_CMD_ISUP:
break;
case ADC_CMD_ISID:
if (client->state == ps_protocol)
{
client->sid = string_to_sid(&line[5]);
client->callback(client, ADC_CLIENT_LOGGING_IN, 0);
ADC_client_set_state(client, ps_identify);
ADC_client_send_info(client);
}
break;
case ADC_CMD_BMSG:
case ADC_CMD_EMSG:
case ADC_CMD_DMSG:
case ADC_CMD_IMSG:
{
struct ADC_chat_message chat;
struct ADC_client_callback_data data;
chat.from_sid = msg->source;
chat.to_sid = msg->target;
data.chat = &chat;
EXTRACT_POS_ARG(msg, 0, chat.message);
client->callback(client, ADC_CLIENT_MESSAGE, &data);
hub_free(chat.message);
break;
}
case ADC_CMD_IINF:
{
struct ADC_hub_info hubinfo;
EXTRACT_NAMED_ARG(msg, "NI", hubinfo.name);
EXTRACT_NAMED_ARG(msg, "DE", hubinfo.description);
EXTRACT_NAMED_ARG(msg, "VE", hubinfo.version);
struct ADC_client_callback_data data;
data.hubinfo = &hubinfo;
client->callback(client, ADC_CLIENT_HUB_INFO, &data);
hub_free(hubinfo.name);
hub_free(hubinfo.description);
hub_free(hubinfo.version);
break;
}
case ADC_CMD_BSCH:
case ADC_CMD_FSCH:
{
client->callback(client, ADC_CLIENT_SEARCH_REQ, 0);
break;
}
case ADC_CMD_BINF:
{
if (msg->source == client->sid)
{
if (client->state == ps_verify || client->state == ps_identify)
{
ADC_client_on_login(client);
}
}
else
{
if (adc_msg_has_named_argument(msg, "ID"))
{
struct ADC_user user;
EXTRACT_NAMED_ARG(msg, "NI", user.name);
EXTRACT_NAMED_ARG(msg, "DE", user.description);
EXTRACT_NAMED_ARG(msg, "VE", user.version);
EXTRACT_NAMED_ARG(msg, "ID", user.cid);
EXTRACT_NAMED_ARG(msg, "I4", user.address);
struct ADC_client_callback_data data;
data.user = &user;
client->callback(client, ADC_CLIENT_USER_JOIN, &data);
hub_free(user.name);
hub_free(user.description);
hub_free(user.version);
hub_free(user.cid);
hub_free(user.address);
}
}
}
case ADC_CMD_ISTA:
/*
if (strncmp(line, "ISTA 000", 8))
{
ADC_client_debug(client, "status: '%s'\n", (start + 9));
}
*/
break;
default:
break;
}
adc_msg_free(msg);
}
static ssize_t ADC_client_recv(struct ADC_client* client)
{
ssize_t size = net_con_recv(client->con, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset);
if (size <= 0)
return size;
client->r_offset += size;
client->recvbuf[client->r_offset] = 0;
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
size_t remaining = client->r_offset;
while ((pos = memchr(start, '\n', remaining)))
{
pos[0] = 0;
ADC_client_on_recv_line(client, start, pos - start);
pos++;
remaining -= (pos - start);
start = pos;
lastPos = pos;
}
if (lastPos)
{
memmove(client->recvbuf, lastPos, remaining);
client->r_offset = remaining;
}
return 0;
}
void ADC_client_send(struct ADC_client* client, char* msg)
{
int ret = net_con_send(client->con, msg, strlen(msg));
#ifdef ADC_CLIENT_DEBUG_PROTO
char* dump = strdup(msg);
dump[strlen(msg) - 1] = 0;
ADC_client_debug(client, "- SEND: '%s'", dump);
free(dump);
#endif
if (ret != strlen(msg))
{
if (ret == -1)
{
if (net_error() != EWOULDBLOCK)
ADC_client_on_disconnected(client);
}
else
{
/* FIXME: Not all data sent! */
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
}
}
}
void ADC_client_send_info(struct ADC_client* client)
{
char binf[11];
snprintf(binf, 11, "BINF %s\n", sid_to_string(client->sid));
client->info = adc_msg_create(binf);
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_NICK, client->nick);
if (client->desc)
{
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_DESCRIPTION, client->desc);
}
adc_msg_add_named_argument_string(client->info, ADC_INF_FLAG_USER_AGENT, PRODUCT "/" VERSION);
adc_cid_pid(client);
ADC_client_send(client, client->info->cache);
}
int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description)
{
memset(client, 0, sizeof(struct ADC_client));
int sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1) return -1;
client->con = net_con_create();
#if 0
/* FIXME */
client->timer = 0; /* FIXME: hub_malloc(sizeof(struct net_timer)); */
#endif
net_con_initialize(client->con, sd, event_callback, client, 0);
#if 0
/* FIXME */
net_timer_initialize(client->timer, timer_callback, client);
#endif
ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname);
client->desc = hub_strdup(description);
return 0;
}
void ADC_client_destroy(struct ADC_client* client)
{
ADC_client_disconnect(client);
#if 0
/* FIXME */
net_timer_shutdown(client->timer);
#endif
hub_free(client->timer);
adc_msg_free(client->info);
hub_free(client->nick);
hub_free(client->desc);
hub_free(client->hub_address);
}
int ADC_client_connect(struct ADC_client* client, const char* address)
{
if (!client->hub_address)
{
if (!ADC_client_parse_address(client, address))
return 0;
client->callback(client, ADC_CLIENT_CONNECTING, 0);
}
int ret = net_connect(net_con_get_sd(client->con), (struct sockaddr*) &client->addr, sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
ADC_client_on_connected(client);
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
if (client->state != ps_conn)
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
ADC_client_set_state(client, ps_conn);
}
}
else
{
ADC_client_on_disconnected(client);
return 0;
}
return 1;
}
static void ADC_client_on_connected(struct ADC_client* client)
{
net_con_update(client->con, NET_EVENT_READ);
client->callback(client, ADC_CLIENT_CONNECTED, 0);
ADC_client_send(client, ADC_HANDSHAKE);
ADC_client_set_state(client, ps_protocol);
}
static void ADC_client_on_disconnected(struct ADC_client* client)
{
net_con_close(client->con);
client->con = 0;
ADC_client_set_state(client, ps_none);
}
static void ADC_client_on_login(struct ADC_client* client)
{
ADC_client_set_state(client, ps_normal);
client->callback(client, ADC_CLIENT_LOGGED_IN, 0);
}
void ADC_client_disconnect(struct ADC_client* client)
{
if (client->con && net_con_get_sd(client->con) != -1)
{
net_con_close(client->con);
client->con = 0;
}
}
static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
{
char* split;
int ssl = 0;
struct hostent* dns;
struct in_addr* addr;
if (!arg)
return 0;
client->hub_address = hub_strdup(arg);
/* Minimum length of a valid address */
if (strlen(arg) < 9)
return 0;
/* Check for ADC or ADCS */
if (!strncmp(arg, "adc://", 6))
ssl = 0;
else if (!strncmp(arg, "adcs://", 7))
ssl = 1;
else
return 0;
/* Split hostname and port (if possible) */
split = strrchr(client->hub_address + 6 + ssl, ':');
if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
return 0;
/* Ensure port number is valid */
int port = strtol(split+1, NULL, 10);
if (port <= 0 || port > 65535)
return 0;
split[0] = 0;
/* Resolve IP address (FIXME: blocking call) */
dns = gethostbyname(client->hub_address + 6 + ssl);
if (dns)
{
addr = (struct in_addr*) dns->h_addr_list[0];
}
// Initialize the sockaddr struct.
memset(&client->addr, 0, sizeof(client->addr));
client->addr.sin_family = AF_INET;
client->addr.sin_port = htons(port);
memcpy(&client->addr.sin_addr, addr, sizeof(struct in_addr));
return 1;
}
void ADC_client_set_callback(struct ADC_client* client, adc_client_cb cb)
{
client->callback = cb;
}

129
src/tools/adcclient.h Normal file
View File

@@ -0,0 +1,129 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_ADC_CLIENT_H
#define HAVE_UHUB_ADC_CLIENT_H
#include "uhub.h"
#define ADC_BUFSIZE 16384
enum ADC_client_state
{
ps_none = 0x00, /* Not connected */
ps_conn = 0x01, /* Connecting... */
ps_protocol = 0x02, /* Have sent HSUP */
ps_identify = 0x04, /* Have sent BINF */
ps_verify = 0x08, /* Have sent HPAS */
ps_normal = 0x10, /* Are fully logged in */
};
struct ADC_client;
enum ADC_client_callback_type
{
ADC_CLIENT_CONNECTING = 1001,
ADC_CLIENT_CONNECTED = 1002,
ADC_CLIENT_DISCONNECTED = 1003,
ADC_CLIENT_LOGGING_IN = 2001,
ADC_CLIENT_PASSWORD_REQ = 2002,
ADC_CLIENT_LOGGED_IN = 2003,
ADC_CLIENT_LOGIN_ERROR = 2004,
ADC_CLIENT_PROTOCOL_STATUS = 3001,
ADC_CLIENT_MESSAGE = 3002,
ADC_CLIENT_CONNECT_REQ = 3003,
ADC_CLIENT_REVCONNECT_REQ = 3004,
ADC_CLIENT_SEARCH_REQ = 3005,
ADC_CLIENT_SEARCH_REP = 3006,
ADC_CLIENT_USER_JOIN = 4001,
ADC_CLIENT_USER_QUIT = 4002,
ADC_CLIENT_USER_UPDATE = 4003,
ADC_CLIENT_HUB_INFO = 5001,
};
struct ADC_hub_info
{
char* name;
char* description;
char* version;
};
struct ADC_chat_message
{
sid_t from_sid;
sid_t to_sid;
char* message;
int flags;
};
struct ADC_user
{
sid_t sid;
char* cid;
char* name;
char* description;
char* address;
char* version;
};
struct ADC_client_callback_data
{
union {
struct ADC_hub_info* hubinfo;
struct ADC_chat_message* chat;
struct ADC_user* user;
};
};
typedef int (*adc_client_cb)(struct ADC_client*, enum ADC_client_callback_type, struct ADC_client_callback_data* data);
struct ADC_client
{
sid_t sid;
enum ADC_client_state state;
struct adc_message* info;
char recvbuf[ADC_BUFSIZE];
char sendbuf[ADC_BUFSIZE];
adc_client_cb callback;
size_t s_offset;
size_t r_offset;
size_t timeout;
struct net_connection* con;
struct net_timer* timer;
struct sockaddr_in addr;
char* hub_address;
char* nick;
char* desc;
};
int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description);
void ADC_client_set_callback(struct ADC_client* client, adc_client_cb);
void ADC_client_destroy(struct ADC_client* client);
int ADC_client_connect(struct ADC_client* client, const char* address);
void ADC_client_disconnect(struct ADC_client* client);
void ADC_client_send(struct ADC_client* client, char* msg);
#endif /* HAVE_UHUB_ADC_CLIENT_H */

View File

@@ -2,105 +2,28 @@
* An ADC client emulator. * An ADC client emulator.
*/ */
#include "uhub.h" #include "adcclient.h"
#define ADC_CLIENTS_DEFAULT 100 #define ADC_CLIENTS_DEFAULT 100
#define ADC_MAX_CLIENTS 25000 #define ADC_MAX_CLIENTS 25000
#define ADC_BUFSIZE 16384
#define ADC_SIDSIZE 4
#define ADC_CID_SIZE 39 #define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768
#define BIG_BUFSIZE 131072
#define TIGERSIZE 24 #define TIGERSIZE 24
#define ADCRUSH "adcrush/0.3"
#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR\n"
#define ADCRUSH "adcrush/0.2"
#define ADC_NICK "[BOT]adcrush" #define ADC_NICK "[BOT]adcrush"
#define ADC_DESC "crash\\stest\\sdummy" #define ADC_DESC "crash\\stest\\sdummy"
struct ADC_client; #define LVL_INFO 1
#define LVL_DEBUG 2
#define LVL_VERBOSE 3
static void ADC_client_on_disconnected(struct ADC_client*); static const char* cfg_uri = 0; /* address */
static void ADC_client_on_connected(struct ADC_client*); static int cfg_debug = 0; /* debug level */
static void ADC_client_on_login(struct ADC_client*); static int cfg_level = 1; /* activity level (0..3) */
static void ADC_client_connect(struct ADC_client*); static int cfg_chat = 0; /* chat mode, allow sending chat messages */
static void ADC_client_disconnect(struct ADC_client*); static int cfg_quiet = 0; /* quiet mode (no output) */
static int ADC_client_create(struct ADC_client* client, int num); static int cfg_clients = ADC_CLIENTS_DEFAULT; /* number of clients */
static void ADC_client_destroy(struct ADC_client* client); static int running = 1;
static int cfg_mode = 0; // See enum operationMode
static char* cfg_host = 0;
static int cfg_port = 0;
static int cfg_debug = 0; /* debug level */
static int cfg_level = 1; /* activity level (0..3) */
static int cfg_chat = 0; /* chat mode, allow sending chat messages */
static int cfg_quiet = 0; /* quiet mode (no output) */
static int cfg_clients = ADC_CLIENTS_DEFAULT; /* number of clients */
static int running = 1;
static struct sockaddr_in saddr;
enum commandMode
{
cm_bcast = 0x01, /* B - broadcast */
cm_dir = 0x02, /* D - direct message */
cm_echo = 0x04, /* E - echo message */
cm_fcast = 0x08, /* F - feature cast message */
cm_c2h = 0x10, /* H - client to hub message */
cm_h2c = 0x20, /* I - hub to client message */
cm_c2c = 0x40, /* C - client to client message */
cm_udp = 0x80, /* U - udp message (client to client) */
};
enum commandValidity
{
cv_protocol = 0x01,
cv_identify = 0x02,
cv_verify = 0x04,
cv_normal = 0x08,
};
enum protocolState
{
ps_none = 0x00, /* none or disconnected */
ps_conn = 0x01, /* connecting... */
ps_protocol = 0x02,
ps_identify = 0x04,
ps_verify = 0x08,
ps_normal = 0x10,
};
enum operationMode
{
mode_performance = 0x01,
mode_bugs = 0x02,
mode_security = 0x04,
mode_log = 0x08,
};
struct commandPattern
{
unsigned char mode; /* see enum commandMode */
char cmd[3];
unsigned char validity; /* see enum commandValidity */
};
const struct commandPattern patterns[] =
{
{ cm_c2h | cm_c2c | cm_h2c, "SUP", cv_protocol | cv_normal }, /* protocol support */
{ cm_bcast | cm_h2c | cm_c2c, "INF", cv_identify | cv_verify | cv_normal }, /* info message */
{ cm_bcast | cm_h2c | cm_c2c | cm_c2h | cm_udp, "STA", cv_protocol | cv_identify | cv_verify | cv_normal }, /* status message */
{ cm_bcast | cm_dir | cm_echo | cm_h2c, "MSG", cv_normal }, /* chat message */
{ cm_bcast | cm_dir | cm_echo | cm_fcast, "SCH", cv_normal }, /* search */
{ cm_dir | cm_udp, "RES", cv_normal }, /* search result */
{ cm_dir | cm_echo, "CTM", cv_normal }, /* connect to me */
{ cm_dir | cm_echo, "RCM", cv_normal }, /* reversed, connect to me */
{ cm_h2c, "QUI", cv_normal }, /* quit message */
{ cm_h2c, "GPA", cv_identify }, /* password request */
{ cm_c2h, "PAS", cv_verify } /* password response */
};
#define MAX_CHAT_MSGS 35 #define MAX_CHAT_MSGS 35
const char* chat_messages[MAX_CHAT_MSGS] = { const char* chat_messages[MAX_CHAT_MSGS] = {
@@ -155,69 +78,21 @@ const char* search_messages[MAX_SEARCH_MSGS] = {
"ANburnout ANps3 TOauto", "ANburnout ANps3 TOauto",
}; };
struct ADC_client
{
int sd;
int num;
sid_t sid;
enum protocolState state;
char info[ADC_BUFSIZE];
char recvbuf[BIG_BUFSIZE];
char sendbuf[BIG_BUFSIZE];
size_t s_offset;
size_t r_offset;
struct event ev_read;
struct event ev_write;
struct event ev_timer;
size_t timeout;
};
static void bot_output(struct ADC_client* client, int level, const char* format, ...)
static void bot_output(struct ADC_client* client, const char* format, ...)
{ {
char logmsg[1024]; char logmsg[1024];
va_list args; va_list args;
va_start(args, format); va_start(args, format);
vsnprintf(logmsg, 1024, format, args); vsnprintf(logmsg, 1024, format, args);
va_end(args); va_end(args);
if (cfg_mode == mode_log)
{ if (cfg_debug >= level)
fprintf(stdout, "%s\n", logmsg); fprintf(stdout, "* [%p] %s\n", client, logmsg);
}
else
{
if (cfg_debug)
fprintf(stdout, "* [%4d] %s\n", client->num, logmsg);
}
}
static void adc_cid_pid(struct ADC_client* client)
{
char seed[64];
char pid[64];
char cid[64];
uint64_t tiger_res1[3];
uint64_t tiger_res2[3];
/* create cid+pid pair */
memset(seed, 0, 64);
snprintf(seed, 64, ADCRUSH "%p/%d", client, (int) client->num);
tiger((uint64_t*) seed, strlen(seed), tiger_res1);
base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
cid[ADC_CID_SIZE] = 0;
pid[ADC_CID_SIZE] = 0;
strcat(client->info, " PD");
strcat(client->info, pid);
strcat(client->info, " ID");
strcat(client->info, cid);
} }
#if 0
static size_t get_wait_rand(size_t max) static size_t get_wait_rand(size_t max)
{ {
static size_t next = 0; static size_t next = 0;
@@ -226,315 +101,9 @@ static size_t get_wait_rand(size_t max)
return ((size_t )(next / 65536) % max); return ((size_t )(next / 65536) % max);
} }
static void client_reschedule_timeout(struct ADC_client* client)
{
size_t next_timeout = 0;
struct timeval timeout = { 0, 0 };
switch (client->state)
{
case ps_conn: next_timeout = 30; break;
case ps_protocol: next_timeout = 30; break;
case ps_identify: next_timeout = 30; break;
case ps_verify: next_timeout = 30; break;
case ps_normal: next_timeout = 120; break;
case ps_none: next_timeout = 120; break;
}
if (client->state == ps_normal || client->state == ps_none)
{
switch (cfg_level)
{
case 0: /* polite */
next_timeout *= 4;
break;
case 1: /* normal */
break;
case 2: /* aggressive */
next_timeout /= 8;
break;
case 3: /* excessive */
next_timeout /= 16;
case 4: /* excessive */
next_timeout /= 32;
}
}
if (client->state == ps_conn)
client->timeout = MAX(next_timeout, 1);
else
client->timeout = get_wait_rand(MAX(next_timeout, 1));
if (!client->timeout) client->timeout++;
timeout.tv_sec = (time_t) client->timeout;
evtimer_add(&client->ev_timer, &timeout);
}
static void set_state_timeout(struct ADC_client* client, enum protocolState state)
{
client->state = state;
client_reschedule_timeout(client);
}
static void send_client(struct ADC_client* client, char* msg)
{
int ret = net_send(client->sd, msg, strlen(msg), UHUB_SEND_SIGNAL);
if (cfg_debug > 1)
{
char* dump = strdup(msg);
dump[strlen(msg) - 1] = 0;
bot_output(client, "- SEND: '%s'", dump);
free(dump);
}
if (ret != strlen(msg))
{
if (ret == -1)
{
if (net_error() != EWOULDBLOCK)
ADC_client_on_disconnected(client);
}
else
{
/* FIXME: Not all data sent! */
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
}
}
}
static void ADC_client_on_connected(struct ADC_client* client)
{
send_client(client, ADC_HANDSHAKE);
set_state_timeout(client, ps_protocol);
bot_output(client, "connected.");
}
static void ADC_client_on_disconnected(struct ADC_client* client)
{
event_del(&client->ev_read);
event_del(&client->ev_write);
net_close(client->sd);
client->sd = -1;
bot_output(client, "disconnected.");
set_state_timeout(client, ps_none);
}
static void ADC_client_on_login(struct ADC_client* client)
{
bot_output(client, "logged in.");
set_state_timeout(client, ps_normal);
}
static void send_client_info(struct ADC_client* client)
{
client->info[0] = 0;
strcat(client->info, "BINF ");
strcat(client->info, sid_to_string(client->sid));
strcat(client->info, " NI" ADC_NICK);
if (cfg_clients > 1)
{
strcat(client->info, "_");
strcat(client->info, uhub_itoa(client->num));
}
strcat(client->info, " VE" ADCRUSH);
strcat(client->info, " DE" ADC_DESC);
strcat(client->info, " I40.0.0.0");
strcat(client->info, " EMuhub@extatic.org");
strcat(client->info, " SL3");
strcat(client->info, " HN1");
strcat(client->info, " HR1");
strcat(client->info, " HO1");
adc_cid_pid(client);
strcat(client->info, "\n");
send_client(client, client->info);
}
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token); static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token);
static int recv_client(struct ADC_client* client)
{
ssize_t size = 0;
if (cfg_mode != mode_performance || (cfg_mode == mode_performance && (get_wait_rand(100) < (90 - (15 * cfg_level)))))
{
size = net_recv(client->sd, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset, 0);
}
else
{
if (get_wait_rand(1000) == 99)
return -1; /* Can break tings badly! :-) */
else
return 0;
}
if (size == 0 || ((size == -1 && net_error() != EWOULDBLOCK)))
return -1;
client->recvbuf[client->r_offset + size] = 0;
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
while ((pos = strchr(start, '\n')))
{
lastPos = pos;
pos[0] = 0;
if (cfg_debug > 1)
{
bot_output(client, "- RECV: '%s'", start);
}
fourcc_t cmd = 0;
if (strlen(start) < 4)
{
bot_output(client, "Unexpected response from hub: '%s'", start);
start = &pos[1];
continue;
}
cmd = FOURCC(start[0], start[1], start[2], start[3]);
switch (cmd)
{
case ADC_CMD_ISUP:
break;
case ADC_CMD_ISID:
if (client->state == ps_protocol)
{
client->sid = string_to_sid(&start[5]);
client->state = ps_identify;
send_client_info(client);
}
break;
case ADC_CMD_IINF:
break;
case ADC_CMD_BSCH:
case ADC_CMD_FSCH:
{
if (get_wait_rand(100) > (90 - (10 * cfg_level)) && cfg_mode == mode_performance)
{
sid_t target = string_to_sid(&start[5]);
const char* what = strstr(&start[5], " AN");
const char* token = strstr(&start[5], " TO");
char* split = 0;
if (!token || !what) break;
token += 3;
what += 3;
split = strchr(what, ' ');
if (!split) break;
else split[0] = '0';
split = strchr(token, ' ');
if (split) split[0] = '0';
perf_result(client, target, what, token);
}
break;
}
case ADC_CMD_BINF:
{
if (strlen(start) > 9)
{
char t = start[9]; start[9] = 0; sid_t sid = string_to_sid(&start[5]); start[9] = t;
if (sid == client->sid)
{
if (client->state == ps_verify || client->state == ps_identify)
{
ADC_client_on_login(client);
}
}
}
break;
}
case ADC_CMD_ISTA:
if (strncmp(start, "ISTA 000", 8))
{
bot_output(client, "status: '%s'\n", (start + 9));
}
break;
default:
break;
}
start = &pos[1];
}
if (lastPos)
{
client->r_offset = strlen(lastPos);
memmove(client->recvbuf, lastPos, strlen(lastPos));
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
}
else
{
// client->r_offset = size;
}
return 0;
}
void ADC_client_connect(struct ADC_client* client)
{
struct timeval timeout = { TIMEOUT_IDLE, 0 };
net_connect(client->sd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in));
set_state_timeout(client, ps_conn);
event_add(&client->ev_read, &timeout);
event_add(&client->ev_write, &timeout);
bot_output(client, "connecting...");
}
void ADC_client_wait_connect(struct ADC_client* client)
{
set_state_timeout(client, ps_none);
}
void ADC_client_disconnect(struct ADC_client* client)
{
if (client->sd != -1)
{
net_close(client->sd);
client->sd = -1;
event_del(&client->ev_read);
event_del(&client->ev_write);
bot_output(client, "disconnected.");
if (running)
{
ADC_client_destroy(client);
ADC_client_create(client, client->num);
ADC_client_connect(client);
}
}
}
static void perf_chat(struct ADC_client* client, int priv) static void perf_chat(struct ADC_client* client, int priv)
{ {
char buf[1024] = { 0, }; char buf[1024] = { 0, };
@@ -559,7 +128,7 @@ static void perf_chat(struct ADC_client* client, int priv)
hub_free(msg); hub_free(msg);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_search(struct ADC_client* client) static void perf_search(struct ADC_client* client)
@@ -582,7 +151,7 @@ static void perf_search(struct ADC_client* client)
} }
strcat(buf, search_messages[r]); strcat(buf, search_messages[r]);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token) static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token)
@@ -601,7 +170,7 @@ static void perf_result(struct ADC_client* client, sid_t target, const char* wha
strcat(buf, " TO"); strcat(buf, " TO");
strcat(buf, token); strcat(buf, token);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_ctm(struct ADC_client* client) static void perf_ctm(struct ADC_client* client)
@@ -616,7 +185,7 @@ static void perf_ctm(struct ADC_client* client)
strcat(buf, " TOKEN111"); strcat(buf, " TOKEN111");
strcat(buf, sid_to_string(client->sid)); strcat(buf, sid_to_string(client->sid));
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
@@ -631,10 +200,9 @@ static void perf_update(struct ADC_client* client)
strcat(buf, uhub_itoa(n)); strcat(buf, uhub_itoa(n));
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_normal_action(struct ADC_client* client) static void perf_normal_action(struct ADC_client* client)
{ {
size_t r = get_wait_rand(5); size_t r = get_wait_rand(5);
@@ -645,7 +213,7 @@ static void perf_normal_action(struct ADC_client* client)
case 0: case 0:
if (p > (90 - (10 * cfg_level))) if (p > (90 - (10 * cfg_level)))
{ {
if (cfg_debug > 1) bot_output(client, "timeout -> disconnect"); bot_output(client, LVL_VERBOSE, "timeout -> disconnect");
ADC_client_disconnect(client); ADC_client_disconnect(client);
} }
break; break;
@@ -653,114 +221,95 @@ static void perf_normal_action(struct ADC_client* client)
case 1: case 1:
if (cfg_chat) if (cfg_chat)
{ {
if (cfg_debug > 1) bot_output(client, "timeout -> chat"); bot_output(client, LVL_VERBOSE, "timeout -> chat");
perf_chat(client, 0); perf_chat(client, 0);
} }
break; break;
case 2: case 2:
if (cfg_debug > 1) bot_output(client, "timeout -> search"); bot_output(client, LVL_VERBOSE, "timeout -> search");
perf_search(client); perf_search(client);
break; break;
case 3: case 3:
if (cfg_debug > 1) bot_output(client, "timeout -> update"); bot_output(client, LVL_VERBOSE, "timeout -> update");
perf_update(client); perf_update(client);
break; break;
case 4: case 4:
if (cfg_debug > 1) bot_output(client, "timeout -> privmsg"); bot_output(client, LVL_VERBOSE, "timeout -> privmsg");
perf_chat(client, 1); perf_chat(client, 1);
break; break;
case 5: case 5:
if (cfg_debug > 1) bot_output(client, "timeout -> ctm/rcm"); bot_output(client, LVL_VERBOSE, "timeout -> ctm/rcm");
perf_ctm(client); perf_ctm(client);
break; break;
} }
client_reschedule_timeout(client);
} }
#endif
void event_callback(int fd, short ev, void *arg) static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data)
{ {
struct ADC_client* client = (struct ADC_client*) arg; switch (type)
if (ev & EV_READ)
{ {
if (recv_client(client) == -1) case ADC_CLIENT_CONNECTING:
{ bot_output(client, LVL_DEBUG, "*** Connecting...");
ADC_client_on_disconnected(client); break;
}
} case ADC_CLIENT_CONNECTED:
bot_output(client, LVL_DEBUG, "*** Connected.");
if (ev & EV_TIMEOUT) break;
{
if (client->state == ps_none) case ADC_CLIENT_DISCONNECTED:
{ bot_output(client, LVL_DEBUG, "*** Disconnected.");
if (client->sd == -1) break;
{
ADC_client_create(client, client->num); case ADC_CLIENT_LOGGING_IN:
} bot_output(client, LVL_DEBUG, "*** Logging in...");
break;
ADC_client_connect(client);
} case ADC_CLIENT_PASSWORD_REQ:
bot_output(client, LVL_DEBUG, "*** Requesting password.");
if (fd == -1)
{ case ADC_CLIENT_LOGGED_IN:
if (client->state == ps_normal && cfg_mode == mode_performance) bot_output(client, LVL_DEBUG, "*** Logged in.");
{ break;
perf_normal_action(client);
} case ADC_CLIENT_LOGIN_ERROR:
} bot_output(client, LVL_DEBUG, "*** Login error");
} break;
if (ev & EV_WRITE) case ADC_CLIENT_MESSAGE:
{ bot_output(client, LVL_DEBUG, " <%s> %s", sid_to_string(data->chat->from_sid), data->chat->message);
if (client->state == ps_conn) break;
{
ADC_client_on_connected(client); case ADC_CLIENT_USER_JOIN:
} bot_output(client, LVL_VERBOSE, " JOIN: %s", data->user->name);
else break;
{
/* FIXME: Call send again */ case ADC_CLIENT_USER_QUIT:
} bot_output(client, LVL_VERBOSE, " QUIT");
break;
case ADC_CLIENT_SEARCH_REQ:
break;
case ADC_CLIENT_HUB_INFO:
bot_output(client, LVL_DEBUG, " Hub: \"%s\" [%s]\n"
" \"%s\"\n", data->hubinfo->name, data->hubinfo->version, data->hubinfo->description);
break;
default:
bot_output(client, LVL_DEBUG, "Not handled event=%d\n", (int) type);
return 0;
break;
} }
return 1;
} }
int ADC_client_create(struct ADC_client* client, int num)
{
struct timeval timeout = { 0, 0 };
memset(client, 0, sizeof(struct ADC_client));
client->num = num;
client->sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client->sd == -1) return -1;
event_set(&client->ev_write, client->sd, EV_WRITE, event_callback, client);
event_set(&client->ev_read, client->sd, EV_READ | EV_PERSIST, event_callback, client);
net_set_nonblocking(client->sd, 1);
timeout.tv_sec = client->timeout;
evtimer_set(&client->ev_timer, event_callback, client);
set_state_timeout(client, ps_none);
return 0;
}
void ADC_client_destroy(struct ADC_client* client)
{
ADC_client_disconnect(client);
evtimer_del(&client->ev_timer);
}
void runloop(size_t clients) void runloop(size_t clients)
{ {
size_t n = 0; size_t n = 0;
@@ -771,23 +320,24 @@ void runloop(size_t clients)
struct ADC_client* c = malloc(sizeof(struct ADC_client)); struct ADC_client* c = malloc(sizeof(struct ADC_client));
client[n] = c; client[n] = c;
ADC_client_create(c, n); char nick[20];
if (n == 0) snprintf(nick, 20, "adcrush_%d", (int) n);
{
ADC_client_connect(c); ADC_client_create(c, nick, "stresstester");
} ADC_client_set_callback(c, handle);
else ADC_client_connect(c, cfg_uri);
{ }
ADC_client_wait_connect(c);
} while (running)
{
event_base_loop(net_get_evbase(), EVLOOP_ONCE);
} }
event_dispatch();
for (n = 0; n < clients; n++) for (n = 0; n < clients; n++)
{ {
ADC_client_destroy(client[n]); ADC_client_destroy(client[n]);
free(client[n]); free(client[n]);
client[n] = 0;
} }
} }
@@ -802,102 +352,29 @@ static void print_usage(const char* program)
{ {
print_version(); print_version();
printf("Usage: %s <mode> (adc://<host>:<port>) [options]\n", program); printf("Usage: %s [adc[s]://<host>:<port>] [options]\n", program);
printf("\n"); printf("\n");
printf(" Modes\n"); printf(" OPTIONS\n");
printf(" perf Do performance testing using multiple clients\n"); printf(" -l <0-3> Level: 0=polite, 1=normal (default), 2=aggressive, 3=excessive.\n");
printf(" bugs Bugs mode, use fuzzer to construct pseudo-random commands.\n"); printf(" -n <num> Number of concurrent connections\n");
printf(" security Perform security tests for the hub.\n");
printf(" log Connect one client to the hub and log the output hub.\n");
printf("\n");
printf(" General options\n");
printf(" -c Allow broadcasting chat messages.\n"); printf(" -c Allow broadcasting chat messages.\n");
printf(" -d Enable debug output.\n"); printf(" -d Enable debug output.\n");
printf(" -q Quiet mode (no output).\n"); printf(" -q Quiet mode (no output).\n");
printf("\n"); printf("\n");
printf(" Performance options:\n");
printf(" -l <0-3> Level: 0=polite, 1=normal (default), 2=aggressive, 3=excessive.\n");
printf(" -n <num> Number of concurrent connections\n");
printf("\n");
exit(0); exit(0);
} }
int set_defaults()
{
switch (cfg_mode)
{
case mode_performance:
break;
case mode_bugs:
break;
case mode_security:
break;
case mode_log:
cfg_quiet = 0;
cfg_debug = 2;
cfg_clients = 1;
break;
}
return 1;
}
int parse_mode(const char* arg)
{
cfg_mode = 0;
if (!strcmp(arg, "perf"))
cfg_mode = mode_performance;
else if (!strcmp(arg, "bugs"))
cfg_mode = mode_bugs;
else if (!strcmp(arg, "security"))
cfg_mode = mode_security;
else if (!strcmp(arg, "log"))
cfg_mode = mode_log;
return cfg_mode;
}
int parse_address(const char* arg) int parse_address(const char* arg)
{ {
char* split; if (!arg || strlen(arg) < 9)
struct hostent* dns; return 0;
struct in_addr* addr;
if (strncmp(arg, "adc://", 6) && strncmp(arg, "adcs://", 7))
if (!arg)
return 0; return 0;
if (strlen(arg) < 9) cfg_uri = arg;
return 0;
if (strncmp(arg, "adc://", 6))
return 0;
split = strrchr(arg+6, ':');
if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
return 0;
cfg_port = strtol(split+1, NULL, 10);
if (cfg_port <= 0 || cfg_port > 65535)
return 0;
split[0] = 0;
dns = gethostbyname(arg+6);
if (dns)
{
addr = (struct in_addr*) dns->h_addr_list[0];
cfg_host = strdup(inet_ntoa(*addr));
}
if (!cfg_host)
return 0;
return 1; return 1;
} }
@@ -905,7 +382,7 @@ int parse_arguments(int argc, char** argv)
{ {
int ok = 1; int ok = 1;
int opt; int opt;
for (opt = 3; opt < argc; opt++) for (opt = 2; opt < argc; opt++)
{ {
if (!strcmp(argv[opt], "-c")) if (!strcmp(argv[opt], "-c"))
cfg_chat = 1; cfg_chat = 1;
@@ -929,30 +406,70 @@ int parse_arguments(int argc, char** argv)
void parse_command_line(int argc, char** argv) void parse_command_line(int argc, char** argv)
{ {
if (argc < 2 || if (argc < 2 ||
!parse_mode(argv[1]) || !parse_address(argv[1]) ||
!set_defaults() ||
!parse_address(argv[2]) ||
!parse_arguments(argc, argv)) !parse_arguments(argc, argv))
{ {
print_usage(argv[0]); print_usage(argv[0]);
} }
} }
#ifndef WIN32
static void handle_signal(int signal, short events, void* arg)
{
switch (signal)
{
case SIGINT:
case SIGTERM:
running = 0;
break;
default:
break;
}
}
static struct event signal_events[10];
static int signals[] =
{
SIGINT, /* Interrupt the application */
SIGTERM, /* Terminate the application */
0
};
void setup_signal_handlers()
{
int i = 0;
for (i = 0; signals[i]; i++)
{
signal_set(&signal_events[i], signals[i], handle_signal, NULL);
signal_add(&signal_events[i], NULL);
}
}
void shutdown_signal_handlers()
{
int i = 0;
for (i = 0; signals[i]; i++)
{
signal_del(&signal_events[i]);
}
}
#endif /* WIN32 */
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
parse_command_line(argc, argv); parse_command_line(argc, argv);
net_initialize(); net_initialize();
event_init(); setup_signal_handlers();
memset(&saddr, 0, sizeof(saddr)); hub_log_initialize(NULL, 0);
saddr.sin_family = AF_INET; hub_set_log_verbosity(1000);
saddr.sin_port = htons(cfg_port);
net_string_to_address(AF_INET, cfg_host, &saddr.sin_addr);
runloop(cfg_clients); runloop(cfg_clients);
shutdown_signal_handlers();
net_destroy(); net_destroy();
return 0; return 0;
} }

89
src/tools/admin.c Normal file
View File

@@ -0,0 +1,89 @@
/**
* A remote uhub admin client.
*/
#include "adcclient.h"
static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data)
{
switch (type)
{
case ADC_CLIENT_CONNECTING:
puts("*** Connecting...");
break;
case ADC_CLIENT_CONNECTED:
puts("*** Connected.");
break;
case ADC_CLIENT_DISCONNECTED:
puts("*** Disconnected.");
break;
case ADC_CLIENT_LOGGING_IN:
puts("*** Logging in...");
break;
case ADC_CLIENT_PASSWORD_REQ:
puts("*** Requesting password.");
case ADC_CLIENT_LOGGED_IN:
puts("*** Logged in.");
break;
case ADC_CLIENT_LOGIN_ERROR:
puts("*** Login error");
break;
case ADC_CLIENT_MESSAGE:
printf(" <%s> %s\n", sid_to_string(data->chat->from_sid), data->chat->message);
break;
case ADC_CLIENT_USER_JOIN:
printf(" JOIN: %s\n", data->user->name);
break;
case ADC_CLIENT_USER_QUIT:
printf(" QUIT\n");
break;
case ADC_CLIENT_SEARCH_REQ:
break;
case ADC_CLIENT_HUB_INFO:
printf(" Hub: \"%s\" [%s]\n"
" \"%s\"\n", data->hubinfo->name, data->hubinfo->version, data->hubinfo->description);
break;
default:
printf("Not handled event=%d\n", (int) type);
return 0;
break;
}
return 1;
}
int main(int argc, char** argv)
{
if (argc < 2)
{
printf("Usage: %s adc[s]://host:port\n", argv[0]);
return 1;
}
struct ADC_client client;
net_initialize();
ADC_client_create(&client, "uhub-admin", "stresstester");
ADC_client_set_callback(&client, handle);
ADC_client_connect(&client, argv[1]);
event_dispatch();
ADC_client_destroy(&client);
net_destroy();
return 0;
}

35
src/tools/fuzzer.h Normal file
View File

@@ -0,0 +1,35 @@
enum commandMode
{
cm_bcast = 0x01, /* B - broadcast */
cm_dir = 0x02, /* D - direct message */
cm_echo = 0x04, /* E - echo message */
cm_fcast = 0x08, /* F - feature cast message */
cm_c2h = 0x10, /* H - client to hub message */
cm_h2c = 0x20, /* I - hub to client message */
cm_c2c = 0x40, /* C - client to client message */
cm_udp = 0x80, /* U - udp message (client to client) */
};
enum commandValidity
{
cv_protocol = 0x01,
cv_identify = 0x02,
cv_verify = 0x04,
cv_normal = 0x08,
};
const struct commandPattern patterns[] =
{
{ cm_c2h | cm_c2c | cm_h2c, "SUP", cv_protocol | cv_normal }, /* protocol support */
{ cm_bcast | cm_h2c | cm_c2c, "INF", cv_identify | cv_verify | cv_normal }, /* info message */
{ cm_bcast | cm_h2c | cm_c2c | cm_c2h | cm_udp, "STA", cv_protocol | cv_identify | cv_verify | cv_normal }, /* status message */
{ cm_bcast | cm_dir | cm_echo | cm_h2c, "MSG", cv_normal }, /* chat message */
{ cm_bcast | cm_dir | cm_echo | cm_fcast, "SCH", cv_normal }, /* search */
{ cm_dir | cm_udp, "RES", cv_normal }, /* search result */
{ cm_dir | cm_echo, "CTM", cv_normal }, /* connect to me */
{ cm_dir | cm_echo, "RCM", cv_normal }, /* reversed, connect to me */
{ cm_h2c, "QUI", cv_normal }, /* quit message */
{ cm_h2c, "GPA", cv_identify }, /* password request */
{ cm_c2h, "PAS", cv_verify } /* password response */
};

View File

@@ -1,6 +1,6 @@
/* /*
* uhub - A tiny ADC p2p connection hub * uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey * Copyright (C) 2007-2010, Jan Vidar Krey
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,100 +25,7 @@
/* #define MEMORY_DEBUG */ /* #define MEMORY_DEBUG */
/* #define DEBUG_SENDQ 1 */ /* #define DEBUG_SENDQ 1 */
#if USE_REGPARM && __GNUC__ >= 3 #include "system.h"
#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
#endif
#if defined(__CYGWIN__) || defined(__MINGW32__)
#ifndef WINSOCK
#define WINSOCK
#endif
#endif
#ifdef WINSOCK
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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
#include <openssl/ssl.h>
#endif
#include "../version.h"
#define uhub_assert assert
#include <event.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#undef HAVE_STRNDUP
#undef HAVE_MEMMEM
#endif
#ifdef MSG_NOSIGNAL
#define UHUB_SEND_SIGNAL MSG_NOSIGNAL
#else
#ifdef MSG_NOPIPE
#define UHUB_SEND_SIGNAL MSG_NOPIPE
#else
#define UHUB_SEND_SIGNAL 0
#endif
#endif
#define SERVER_PORT 1511
#define SERVER_ADDR_IPV6 "::"
#define SERVER_ADDR_IPV4 "0.0.0.0"
#define SERVER_BACKLOG 50
#ifndef WIN32 #ifndef WIN32
#define SERVER_CONFIG "/etc/uhub/uhub.conf" #define SERVER_CONFIG "/etc/uhub/uhub.conf"
@@ -134,10 +41,8 @@
#define TIMEOUT_CONNECTED 15 #define TIMEOUT_CONNECTED 15
#define TIMEOUT_HANDSHAKE 30 #define TIMEOUT_HANDSHAKE 30
#define TIMEOUT_SENDQ 120 #define TIMEOUT_SENDQ 120
#define TIMEOUT_IDLE 7200
#define TIMEOUT_STATS 60 #define TIMEOUT_STATS 60
#define MAX_CLIENTS 512
#define MAX_CID_LEN 39 #define MAX_CID_LEN 39
#define MAX_NICK_LEN 64 #define MAX_NICK_LEN 64
#define MAX_UA_LEN 32 #define MAX_UA_LEN 32
@@ -146,24 +51,18 @@
#define MAX_RECV_BUF 65535 #define MAX_RECV_BUF 65535
#define MAX_SEND_BUF 65535 #define MAX_SEND_BUF 65535
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#include "adc/adcconst.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "adc/adcconst.h"
#include "util/ipcalc.h" #include "util/ipcalc.h"
#include "util/list.h" #include "util/list.h"
#include "util/log.h" #include "util/log.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/misc.h" #include "util/misc.h"
#include "util/timeout.h"
#include "util/tiger.h" #include "util/tiger.h"
#include "adc/sid.h" #include "adc/sid.h"

View File

@@ -54,6 +54,11 @@ void list_clear(struct linked_list* list, void (*free_handle)(void* ptr))
void list_append(struct linked_list* list, void* data_ptr) void list_append(struct linked_list* list, void* data_ptr)
{ {
struct node* new_node = (struct node*) hub_malloc_zero(sizeof(struct node)); struct node* new_node = (struct node*) hub_malloc_zero(sizeof(struct node));
if (!new_node)
{
LOG_FATAL("Unable to allocate memory");
return;
}
new_node->ptr = data_ptr; new_node->ptr = data_ptr;
if (list->last) if (list->last)

View File

@@ -47,7 +47,7 @@ void internal_debug_print_leaks()
size_t n = 0; size_t n = 0;
size_t leak = 0; size_t leak = 0;
size_t count = 0; size_t count = 0;
LOG_MEMORY("--- exit (allocs: %d, size: %zu) ---", hub_alloc_count, hub_alloc_size); LOG_MEMORY("--- exit (allocs: %d, size: " PRINTF_SIZE_T ") ---", hub_alloc_count, hub_alloc_size);
for (; n < UHUB_MAX_ALLOCS; n++) for (; n < UHUB_MAX_ALLOCS; n++)
{ {
@@ -55,11 +55,11 @@ void internal_debug_print_leaks()
{ {
leak += hub_allocs[n].size; leak += hub_allocs[n].size;
count++; count++;
LOG_MEMORY("leak %p size: %zu (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2); LOG_MEMORY("leak %p size: " PRINTF_SIZE_T " (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2);
} }
} }
LOG_MEMORY("--- done (allocs: %d, size: %zu, peak: %d/%zu, oom: %zu) ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom); LOG_MEMORY("--- done (allocs: %d, size: " PRINTF_SIZE_T ", peak: %d/" PRINTF_SIZE_T ", oom: " PRINTF_SIZE_T ") ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom);
} }
#endif /* REALTIME_MALLOC_TRACKING */ #endif /* REALTIME_MALLOC_TRACKING */
@@ -107,7 +107,7 @@ 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_count = MAX(hub_alloc_count, hub_alloc_peak_count);
hub_alloc_peak_size = MAX(hub_alloc_size, hub_alloc_peak_size); hub_alloc_peak_size = MAX(hub_alloc_size, hub_alloc_peak_size);
LOG_MEMORY("%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: %zu}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size); LOG_MEMORY("%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: " PRINTF_SIZE_T "}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size);
break; break;
} }
} }
@@ -141,7 +141,7 @@ void internal_debug_mem_free(void* ptr)
hub_allocs[n].size = 0; hub_allocs[n].size = 0;
hub_allocs[n].stack1 = 0; hub_allocs[n].stack1 = 0;
hub_allocs[n].stack2 = 0; hub_allocs[n].stack2 = 0;
LOG_MEMORY("free %p (bt: %p %p) {allocs: %d, size: %zu}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size); LOG_MEMORY("free %p (bt: %p %p) {allocs: %d, size: " PRINTF_SIZE_T "}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
malloc_slot = n; malloc_slot = n;
free(ptr); free(ptr);
return; return;

View File

@@ -45,12 +45,15 @@ static int is_printable(unsigned char c)
char* strip_white_space(char* string) char* strip_white_space(char* string)
{ {
char* pos; char* pos;
if (!string)
return "";
while (string[0] && is_white_space(string[0])) string++; while (string[0] && is_white_space(string[0])) string++;
if (!*string) if (!*string)
return 0; return string;
/* Strip appending whitespace */ /* Strip appending whitespace */
pos = &string[strlen(string)-1]; pos = &string[strlen(string)-1];
while (&string[0] < &pos[0] && is_white_space(pos[0])) { pos[0] = 0; pos--; } while (&string[0] < &pos[0] && is_white_space(pos[0])) { pos[0] = 0; pos--; }

View File

@@ -47,10 +47,13 @@ extern uint64_t tiger_sboxes[4*256];
ROUND(b, c, a, x7, mul) ROUND(b, c, a, x7, mul)
void tiger_compress(uint64_t* str, uint64_t state[3]) { void tiger_compress(uint64_t* str, uint64_t state[3]) {
uint64_t a, b, c, swap; uint64_t a, b, c;
uint64_t x0, x1, x2, x3, x4, x5, x6, x7; uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
uint64_t aa, bb, cc; uint64_t aa, bb, cc;
#if PASSES > 3
uint64_t swap;
size_t pass_no; size_t pass_no;
#endif
a = state[0]; a = state[0];
b = state[1]; b = state[1];
c = state[2]; c = state[2];
@@ -107,7 +110,8 @@ void tiger_compress(uint64_t* str, uint64_t state[3]) {
x7 -= x6 ^ 0x0123456789ABCDEFULL; x7 -= x6 ^ 0x0123456789ABCDEFULL;
PASS(b, c, a, 9); PASS(b, c, a, 9);
#if PASSES > 3
for (pass_no = 3; pass_no < PASSES; pass_no++) for (pass_no = 3; pass_no < PASSES; pass_no++)
{ {
x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5ULL; x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5ULL;
@@ -134,7 +138,8 @@ void tiger_compress(uint64_t* str, uint64_t state[3]) {
c = b; c = b;
b = swap; b = swap;
} }
#endif
a ^= aa; a ^= aa;
b -= bb; b -= bb;
c += cc; c += cc;

126
src/util/timeout.c Normal file
View File

@@ -0,0 +1,126 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along wtimeout_evtith this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#include "util/timeout.h"
void timeout_evt_initialize(struct timeout_evt* t, timeout_evt_cb cb, void* ptr)
{
t->callback = cb;
t->ptr = ptr;
t->prev = 0;
t->next = 0;
}
void timeout_evt_reset(struct timeout_evt* t)
{
t->prev = 0;
t->next = 0;
}
int timeout_evt_is_scheduled(struct timeout_evt* t)
{
if (!t) return 0;
return !!t->prev;
}
void timeout_queue_initialize(struct timeout_queue* t, time_t now, size_t max)
{
t->last = now;
t->max = max;
t->events = hub_malloc_zero(max * sizeof(struct timeout_evt*));
}
void timeout_queue_shutdown(struct timeout_queue* t)
{
hub_free(t->events);
t->events = 0;
t->max = 0;
}
size_t timeout_queue_process(struct timeout_queue* t, time_t now)
{
size_t pos;
size_t events = 0;
struct timeout_evt* evt = 0;
for (pos = t->last; pos < now; pos++)
{
while ((evt = t->events[pos % t->max]))
{
timeout_queue_remove(t, evt);
timeout_evt_reset(evt);
evt->callback(evt);
events++;
}
}
t->last = now;
return events;
}
void timeout_queue_insert(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds)
{
struct timeout_evt* first;
size_t pos = ((t->last + seconds) % t->max);
evt->timestamp = t->last + seconds;
evt->next = 0;
first = t->events[pos];
if (!first)
{
t->events[pos] = evt;
evt->prev = evt;
}
else
{
evt->prev = first->prev;
first->prev = evt;
}
}
void timeout_queue_remove(struct timeout_queue* t, struct timeout_evt* evt)
{
size_t pos = (evt->timestamp % t->max);
struct timeout_evt* first = t->events[pos];
if (!first)
return;
if (first == evt)
{
if (first->next)
first->next->prev = first->prev;
t->events[pos] = first->next;
}
else
{
evt->prev->next = evt->next;
if (evt->next)
evt->next->prev = evt->prev;
else
first->prev = evt->prev;
}
}
void timeout_queue_reschedule(struct timeout_queue* t, struct timeout_evt* evt, size_t seconds)
{
if (timeout_evt_is_scheduled(evt))
timeout_queue_remove(t, evt);
timeout_queue_insert(t, evt, seconds);
}

56
src/util/timeout.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_TIMEOUT_HANDLER_H
#define HAVE_UHUB_TIMEOUT_HANDLER_H
struct timeout_evt;
struct timeout_queue;
typedef void (*timeout_evt_cb)(struct timeout_evt*);
struct timeout_evt
{
time_t timestamp;
timeout_evt_cb callback;
void* ptr;
struct timeout_evt* prev;
struct timeout_evt* next;
};
void timeout_evt_initialize(struct timeout_evt*, timeout_evt_cb, void* ptr);
void timeout_evt_reset(struct timeout_evt*);
int timeout_evt_is_scheduled(struct timeout_evt*);
struct timeout_queue
{
time_t last;
size_t max;
struct timeout_evt** events;
};
void timeout_queue_initialize(struct timeout_queue*, time_t now, size_t max);
void timeout_queue_shutdown(struct timeout_queue*);
size_t timeout_queue_process(struct timeout_queue*, time_t now);
void timeout_queue_insert(struct timeout_queue*, struct timeout_evt*, size_t seconds);
void timeout_queue_remove(struct timeout_queue*, struct timeout_evt*);
void timeout_queue_reschedule(struct timeout_queue*, struct timeout_evt*, size_t seconds);
#endif /* HAVE_UHUB_TIMEOUT_HANDLER_H */