Compare commits

...

156 Commits

Author SHA1 Message Date
Jan Vidar Krey
d2da49d41a Added .gitignore file. 2009-08-02 23:44:23 +02:00
Jan Vidar Krey
4666311516 Add a quit reason to the log messages printed by !log. 2009-08-02 22:53:25 +02:00
Jan Vidar Krey
1f24bd6812 Fix autotests. 2009-08-02 22:29:22 +02:00
Jan Vidar Krey
0e1cd903da Make sure we create enough sids as there are socket descriptors. 2009-08-02 22:29:12 +02:00
Jan Vidar Krey
4931dc5dcb Added call functionality to figure out the maximum number of sockets (file descriptors) available on system. 2009-08-02 22:28:34 +02:00
Jan Vidar Krey
077bffd74f Fix capped whoip/history messages due to limit of 1024 bytes imposed wrongly on outgoing server generated messages. 2009-08-02 21:58:12 +02:00
Jan Vidar Krey
cfb8a9f322 Started using the new connection abstraction. 2009-08-02 21:46:57 +02:00
Jan Vidar Krey
653cfb285e Started working on abstracting the connection data away from the user struct. 2009-08-02 21:37:55 +02:00
Jan Vidar Krey
053fb30192 Build fix. 2009-08-02 21:07:16 +02:00
Jan Vidar Krey
9bd0286c01 Fix bug #3, sid allocation overflow. May lead to double SIDs being given out. 2009-08-02 21:04:10 +02:00
Jan Vidar Krey
b78d48795b !history had a wrong help description. 2009-08-02 19:26:21 +02:00
Jan Vidar Krey
9b58ba6516 Use correct prefix for log command. 2009-07-28 02:17:57 +02:00
Jan Vidar Krey
f322fbb197 Fix !log command, split it up into multiple messages, and allow for searches. 2009-07-28 02:02:19 +02:00
Jan Vidar Krey
80348044c3 Make sure history messages are not escaped. 2009-07-26 18:22:53 +02:00
Jan Vidar Krey
31d4b0f0b1 Fix history - do not cache private messages. 2009-07-26 15:08:34 +02:00
Jan Vidar Krey
10615a9a1a Whitespace 2009-07-26 06:32:15 +02:00
Jan Vidar Krey
7b44036480 print ip address when using whoip. 2009-07-26 06:30:48 +02:00
Jan Vidar Krey
112fa2f845 Fixes to tests. 2009-07-26 06:27:16 +02:00
Jan Vidar Krey
945c6be14c Added tests for ip_convert_address_to_range 2009-07-26 06:21:22 +02:00
Jan Vidar Krey
099ed6dbe2 Fix autotest 2009-07-26 06:06:27 +02:00
Jan Vidar Krey
444f991f44 Fix bug #44 - [Request] IP log in the memory 2009-07-26 06:03:43 +02:00
Jan Vidar Krey
b125ffe3c1 Fix bug #52 - [Request] Chat history command 2009-07-26 05:23:56 +02:00
Jan Vidar Krey
76b84499bc Fix bug #46: [Request] A broadcast command.
Use !broadcast <message>
2009-07-26 04:47:43 +02:00
Jan Vidar Krey
6358c7f9cd Fix bug #45: [Request] Whoip command.
Rewrote patches from Zoltan to support ip ranges and multiple results per IP.
Needed to make sure IPv6 mapped IPv4 addresses were converted to proper IPv4 addresses after accept().
2009-07-26 04:31:36 +02:00
Jan Vidar Krey
041ce7a1fb Generalized the IP range and mask parsing code. 2009-07-26 03:56:55 +02:00
Jan Vidar Krey
78bb1d3527 Typo - compilefix. 2009-07-26 02:06:02 +02:00
Jan Vidar Krey
48f3cae22b Ensure we delete the global evtimer only if it is initialized. 2009-07-26 02:05:01 +02:00
Jan Vidar Krey
817250c528 Fix wrong #if to #ifdef 2009-07-26 01:53:53 +02:00
Jan Vidar Krey
f176e790e2 Whitespace fixes. 2009-07-26 01:53:01 +02:00
Jan Vidar Krey
367871e476 Renamed all "struct user" to hub_user in order to resolve a naming conflict on OpenWRT.
Basically: sed -i 's/struct user/struct hub_user/g' `find -type f`
2009-07-26 01:47:17 +02:00
Jan Vidar Krey
2ac5cc19cb Removed plugin.h, not in use. 2009-07-26 01:39:16 +02:00
Jan Vidar Krey
6e5d28c2d4 Rework logging code to be able to turn it off completely. 2009-07-26 01:38:38 +02:00
Jan Vidar Krey
5048ff9ae5 Whitespace fixes. 2009-07-26 00:58:25 +02:00
Jan Vidar Krey
36a07e3f7e Reorganized sources slightly. 2009-07-25 20:05:27 +02:00
Jan Vidar Krey
e281f61472 Add support for better pipelining of commands, in order to reduce the number of send() calls. 2009-07-25 03:54:59 +02:00
Jan Vidar Krey
bb27ff617c Re-fix chat_is_privileged. 2009-07-25 03:33:36 +02:00
Jan Vidar Krey
dc90245ade No need to store event mask in the user object since libevent already does it for us. 2009-07-25 03:26:59 +02:00
Jan Vidar Krey
0ec4913e15 Debug for send queue fix. 2009-07-25 03:24:06 +02:00
Jan Vidar Krey
61d639bfa2 Fix to hub_sendq_is_empty in order to prevent event_add calls. 2009-07-25 03:23:06 +02:00
Jan Vidar Krey
adeaf23f9c Kept spinning in send() 2009-07-19 14:45:15 +02:00
Jan Vidar Krey
03d3ffd20f Fix socket error due to EWOULDBLOCK. 2009-07-19 14:29:33 +02:00
Jan Vidar Krey
bbae2603b0 Make sure we detect send errors. 2009-07-19 03:39:11 +02:00
Jan Vidar Krey
5f0c84f46a Fix shutdown problem and reduce event_{add,del,set} calls. 2009-07-19 03:12:47 +02:00
Jan Vidar Krey
b02618d19c Bad mistake - never added message to send queue. 2009-07-19 02:46:01 +02:00
Jan Vidar Krey
927faf70fc Re-enabled send queue fixes. This will more aggressively prevent unimportant messages (like searches) to be forwarded to slow clients that cannot swallow what is sent to it. This should reduce memory usage somewhat on really large hubs. 2009-07-19 02:31:23 +02:00
Jan Vidar Krey
4a173bf066 Fix some nasty bugs related to read/write events and timeout events.
This would have caused users not being able to log in, and in some cases
100% cpu usage.
2009-07-19 02:12:50 +02:00
Jan Vidar Krey
abd097acf0 This is a somewhat risky patch, but it has been intended for quite some time:
Remove the libevent handler for write events, only use one common event handler for both reading and writing.
2009-07-09 17:03:31 +02:00
Jan Vidar Krey
3fdbccb028 Fix bug #47 - Enable -ggdb instead of -g for DEBUG builds.
RELEASE builds are built with -O3 instead of -Os.
2009-07-09 17:01:45 +02:00
Jan Vidar Krey
3db2ec5e22 Added macros that can possibly make it easier to optimize functions using forced inlining and regparm. 2009-07-09 17:01:30 +02:00
Jan Vidar Krey
e68cbd0cde Minor cleanups of old authentication stuff, and some documentation. 2009-07-03 01:29:04 +02:00
Jan Vidar Krey
98bffd93e9 Fix stupid crash on empty command. 2009-07-01 11:31:55 +02:00
Jan Vidar Krey
e53119e92c Server did not answer due to wrong checks. 2009-07-01 09:50:46 +02:00
Jan Vidar Krey
ee0ea5a427 Crash fix. 2009-06-30 22:15:08 +02:00
Jan Vidar Krey
aa7be1dc4b Fix a command parse error output problem, plus some minor cleaning up. 2009-06-30 11:48:58 +02:00
Jan Vidar Krey
0ef248759c Minor cleanups.
Enabled !crash command if compiled with debug (not release).
2009-06-29 23:22:13 +02:00
Jan Vidar Krey
5b5d9faf96 Bumped to 0.3.0-rc3. 2009-06-26 01:16:18 +02:00
Jan Vidar Krey
1f7f6a43f9 Fixed small memory leak. 2009-06-26 01:16:07 +02:00
Jan Vidar Krey
3cf005a08e Fixed command parsing for in hub user commands.
Added a framework for automatic syntax checks, and correct number
of arguments to commands.
2009-06-26 01:15:06 +02:00
Jan Vidar Krey
f3c5fced47 Documentation 2009-06-25 22:05:40 +02:00
Jan Vidar Krey
9c49f07826 Fixed the format of the git revision.
Removed the product title.
2009-06-25 22:04:48 +02:00
Jan Vidar Krey
0b59941102 Minor optimization. 2009-06-25 17:35:59 +02:00
Jan Vidar Krey
5f3f2d4f4d Autotest crash fix. 2009-06-25 17:31:39 +02:00
Jan Vidar Krey
a3d4c8dbc3 Windows fix. 2009-06-25 17:29:50 +02:00
Jan Vidar Krey
7e3a26b0f3 Winsock fixes for shutdown() - typo 2009-06-25 17:07:21 +02:00
Jan Vidar Krey
9ebb38ae15 Winsock fixes for shutdown() 2009-06-25 17:05:59 +02:00
Jan Vidar Krey
5b29a3b403 Bump to 0.3.0 release candidate 2. 2009-06-25 09:29:59 +02:00
Jan Vidar Krey
75c4272a1b Fix problem with the !stats byte counter. 2009-06-25 09:29:23 +02:00
Jan Vidar Krey
f272280faf Old versions of git 0.5 does not support the git show --oneline. - Maybe this works? 2009-06-24 09:18:03 +02:00
Jan Vidar Krey
b1d4b1288f Bump to 0.3.0-rc1 2009-06-23 23:29:27 +02:00
Jan Vidar Krey
ddba669af0 Some basic work on getting bans working.
Basically now it can ban a user (nick + cid), it will be added to the
ban list temporarily, and will not be enabled if you restart the hub.
A banned user will automatically be kicked.

unban does not work correctly.
2009-06-23 23:16:09 +02:00
Jan Vidar Krey
2ad2b66db3 Add a git revision to all debug builds... 2009-06-23 16:11:30 +02:00
Jan Vidar Krey
ca33461851 Suppress send() or recv() errors from logs. They happen quite often and are not considered errors. 2009-06-23 01:57:55 +02:00
Jan Vidar Krey
4abdc3edbd Cleanup read/write socket handling somewhat. 2009-06-23 01:57:26 +02:00
Jan Vidar Krey
90078ad4b6 Minor cleanups and some work to prepare SSL. 2009-06-23 01:56:37 +02:00
Jan Vidar Krey
3bd5c36455 SSL work. 2009-06-23 01:09:55 +02:00
Jan Vidar Krey
8f0943621e Dont set socket buffers. 2009-06-22 21:13:41 +02:00
Jan Vidar Krey
155350b61b Fixed crash bug #33 2009-06-22 21:05:02 +02:00
Jan Vidar Krey
1c58120c03 Oportunistic write. 2009-06-22 20:25:22 +02:00
Jan Vidar Krey
1d9acece34 Ensure we set a max recv and send buffer per user, and that it does not
exceed the one used internally by the application.
2009-06-22 19:50:10 +02:00
Jan Vidar Krey
57fd872f14 Added a state check for protocol negotiation.
Will be used to negotiate SSL.
2009-06-22 19:38:24 +02:00
Jan Vidar Krey
ca7544df9b Cleanups. 2009-06-22 19:37:56 +02:00
Jan Vidar Krey
c7777e2624 Added functions:
* net_get_recvbuf_size
* net_set_recvbuf_size
* net_get_sendbuf_size
* net_set_sendbuf_size

Did some minor cleanups.
2009-06-22 19:36:55 +02:00
Jan Vidar Krey
b2d543d433 Started work on SSL 2009-06-22 18:44:07 +02:00
Jan Vidar Krey
ff47281197 Added a generic way to reset last read/write variables. 2009-06-22 18:38:39 +02:00
Jan Vidar Krey
ddc91d1640 Make sure we close stdout, stdin and stderr after forking to background in order to properly detach from the TTY. 2009-06-22 18:36:48 +02:00
Jan Vidar Krey
0d084a5e14 Move to rc0 2009-06-22 17:32:38 +02:00
Jan Vidar Krey
e6e26a02e7 Added a known crash for the admin only to use if compiled with CRASH_DEBUG enabled. 2009-06-22 01:18:51 +02:00
Jan Vidar Krey
ea3cd1bd90 Work on optimizing send(), to use fewer send function calls. 2009-06-21 14:21:34 +02:00
Jan Vidar Krey
7f24238ab5 Disable sendq debugging. 2009-06-20 22:46:11 +02:00
Jan Vidar Krey
1d2d4e74f6 !stats did not work. 2009-06-18 01:46:17 +02:00
root
5250fdaf57 Fix bug #38 - Pid file support. 2009-06-17 12:52:49 +02:00
Jan Vidar Krey
7ddfd52dc7 Fix bug #34 - Disable admin\op account in example users.conf since it is being installed by default. 2009-06-01 19:55:03 +02:00
Jan Vidar Krey
513ab422f2 Compile fix. 2009-06-01 14:34:23 +02:00
Jan Vidar Krey
0eb91763fa Potential crash fix. 2009-06-01 01:52:57 +02:00
Jan Vidar Krey
507f429035 Fix send queue issue. 2009-05-28 23:44:28 +02:00
Jan Vidar Krey
b1ab64242e Renamed a function. 2009-05-28 01:48:31 +02:00
Jan Vidar Krey
8b90f79bac Work in progress on optimizing the send() function calls, to use as few as possible.
(Although, this does not enable that code).
2009-05-28 01:47:48 +02:00
Jan Vidar Krey
8f7cc0b7a7 Fixed MAX and MIN macros. 2009-05-28 01:45:36 +02:00
Jan Vidar Krey
4812a5968b Added an ADC redirector script, which is useful to run from inetd, xinetd
or similar in case you move your hub to another machine.
It will accept ADC connections and redirect clients to the new hub
instead.
2009-05-28 01:33:23 +02:00
Jan Vidar Krey
8b5bfdd922 Compile fix. 2009-05-27 18:05:34 +02:00
Jan Vidar Krey
860310caff Massive restructuring. 2009-05-26 21:05:06 +02:00
Jan Vidar Krey
8167d79f5a Large reorganizations of the code base. 2009-05-26 19:46:51 +02:00
Jan Vidar Krey
9706a0a501 Fix compiler warning (bug #30) 2009-05-24 21:07:16 +02:00
Jan Vidar Krey
9309c925d3 Started working on new pipelines for sending and receiving data.
This will be useful for the next step; SSL.

(NOTE: This code is very chatty about debug messages)
2009-05-19 22:57:50 +02:00
Jan Vidar Krey
9a3a5bc2de Make sure the send() signature is correct, buf should be const. 2009-05-19 22:36:45 +02:00
Jan Vidar Krey
e382e24337 Fix crash due to user->hub deref in acl handling. 2009-05-19 16:40:14 +02:00
Jan Vidar Krey
be4ff1d8cc Fix command parsing for in-hub commands. 2009-05-19 11:22:57 +02:00
Jan Vidar Krey
aa18ac047d Crash fix 2009-05-19 09:38:57 +02:00
Jan Vidar Krey
e120d5c76d Minor cleanup - this code crashes. 2009-05-19 09:15:14 +02:00
Jan Vidar Krey
6853e92f89 Move user_is_protected() and user_is_registered() into user.h/.c 2009-05-18 17:52:30 +02:00
Jan Vidar Krey
1dbf2640d2 More API fixes; remove implicit relationship between hub and user
in APIs.
2009-05-18 16:30:17 +02:00
Jan Vidar Krey
caec28f63f Warn on bad UTF-8 in the configuration file. 2009-05-16 12:48:17 +02:00
Jan Vidar Krey
5ea5efb875 Smome user manager functions did not have the uman_ prefix. 2009-05-16 12:42:30 +02:00
Jan Vidar Krey
326fcc467c Moved the update_user_info code into user_update_info 2009-05-16 12:32:48 +02:00
Jan Vidar Krey
078470ce64 Minor cleanup 2009-05-16 12:25:28 +02:00
Jan Vidar Krey
82ac450b4b Fixed further memory leaks in autotests. 2009-05-16 04:03:00 +02:00
Jan Vidar Krey
b4f24b21f9 Document bandwidth optimization potential. 2009-05-16 03:45:05 +02:00
Jan Vidar Krey
968266b22f Fix memory leaks. 2009-05-16 03:44:51 +02:00
Jan Vidar Krey
548867de10 Removed ADC_UDP_OPERATION code as it is not used or needed. on_kick is also gone. 2009-05-16 03:14:20 +02:00
Jan Vidar Krey
953db2dcbc Fixed some autotest memory leaks. 2009-05-16 03:06:14 +02:00
Jan Vidar Krey
6e4ac1355f Fix autotest crashers. 2009-05-16 02:33:43 +02:00
Jan Vidar Krey
604364ffa5 Fixed various code deprecations
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-05-15 18:45:26 +02:00
Jan Vidar Krey
6cc1af5671 Disable code to prevent warnings. 2009-05-15 16:52:55 +02:00
Jan Vidar Krey
15e2053699 Fix #28 - Request: +/! characters for command handling (FleetCommand) 2009-05-15 16:52:04 +02:00
Jan Vidar Krey
df1e832a3c Started working on a red-black tree implementation, need to speed up
certain operations, such as SID to user lookups, and nick to user.
2009-05-01 17:07:38 +02:00
Jan Vidar Krey
4c4cb4fb36 Dont allow clients that do not support BASE
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-04-13 05:31:41 +02:00
Jan Vidar Krey
e49f9d4d30 Added kick support
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-04-09 00:48:00 +02:00
Jan Vidar Krey
e73a931243 Ensure we do not allow update of certain elements.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-27 11:12:50 +01:00
Jan Vidar Krey
ae017af758 Log version and method of libevent()
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-24 23:32:39 +01:00
Jan Vidar Krey
7a02f92a4c Cleanup after creating debian packages.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-24 23:16:09 +01:00
Jan Vidar Krey
adeebb92a0 Added manual page. 2009-03-24 23:14:04 +01:00
Jan Vidar Krey
26f1864c1f Don't crash if one specify '-S' or '-s' and an invalid configuration file. 2009-03-24 23:10:51 +01:00
Jan Vidar Krey
c14fa3c3a9 Added more debugging info for mainloop bug #16 - In addition to small fixes to it.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-24 22:06:26 +01:00
Jan Vidar Krey
dfd2191103 White space cleanups. 2009-03-24 18:39:39 +01:00
Jan Vidar Krey
0042344054 Better dpkg system. 2009-03-24 18:38:59 +01:00
Jan Vidar Krey
8af965c0ca Fixed utf8 parse issue.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-24 00:21:38 +01:00
Jan Vidar Krey
b3d3dcdb44 Actually do upload.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:45:39 +01:00
Jan Vidar Krey
cb6190c5b4 FreeBSD fix.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:39:34 +01:00
Jan Vidar Krey
82ad62602d 0.2.8 release candidate.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:36:29 +01:00
Jan Vidar Krey
6d34bdd7e2 Added upload script.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:32:32 +01:00
Jan Vidar Krey
c2832e59c0 Added build script setup for easy publishing...
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:30:51 +01:00
Jan Vidar Krey
cf23c82c16 Added upload support.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 23:02:59 +01:00
Jan Vidar Krey
8bf0fd424a Added upload support. 2009-03-23 23:02:52 +01:00
Jan Vidar Krey
8f8284eb29 Ensure we build source .zip file. 2009-03-23 22:54:59 +01:00
Jan Vidar Krey
015c3368bd Added new script for building sources only.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 22:51:53 +01:00
Jan Vidar Krey
9186b441aa Minor build system tweaks.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 22:47:08 +01:00
Jan Vidar Krey
74af392e80 Stop in case of error.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 22:40:15 +01:00
Jan Vidar Krey
3a270564d2 Fixed up admin scripts.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 22:36:45 +01:00
Jan Vidar Krey
f0938e8afa Fixed up build scripts somewhat. 2009-03-23 22:33:45 +01:00
Jan Vidar Krey
156c137237 Autotest for bug #12
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 21:55:24 +01:00
Jan Vidar Krey
7aeb8651ba Fix bug #12: asserts in adc_msg_parse -> enabled strict utf8 parsing.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 21:47:05 +01:00
Jan Vidar Krey
ab4eb6db3d Document 0.2.8 changes. 2009-03-23 16:51:06 +01:00
Jan Vidar Krey
13a8700554 Make sure logs do not output configured messages, but rather code names.
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 15:47:54 +01:00
Jan Vidar Krey
5d5dda2f9b Always obtain IP address during accept(), and not do it later as a call to getsockname().
Signed-off-by: Jan Vidar Krey <janvidar@extatic.org>
2009-03-23 15:05:27 +01:00
Jan Vidar Krey
95b741bb5e More message tests. 2009-03-23 14:58:15 +01:00
Jan Vidar Krey
90abf64e3a Do explicit logging in src/message.c 2009-03-23 08:18:25 +01:00
97 changed files with 4568 additions and 3750 deletions

2
.gitignore vendored Normal file
View File

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

View File

@@ -1,3 +1,9 @@
0.2.8:
- Fix bug #13: getsockname() failure, use sockaddr from accept() instead.
- Fix bug #10: Improve logging, ensure logs are machine readable.
- Fix bug #12: asserts in adc_msg_parse -> enabled strict utf8 parsing.
0.2.7:
- Fixed a nasty crash (bug #11), Thanks Toast for finding it.
- Fix bug #9 - net_get_peer_address() failure on CentOS/Xen configurations.

View File

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

View File

@@ -6,25 +6,30 @@ else
HOST_MACHINE=`uname -m | tr [:upper:] [:lower:] | sed s/i686/i386/ | sed s/x86_64/amd64/ | sed s/ppc64/powerpc/`
fi
BINSUFFIX=
MAKEARGS=
MAKE=make
WANTZIP=0
if [ "${HOST_SYSTEM}" = "mingw32_nt-5.1" ]; then
HOST_SYSTEM=win32
BINARY=uhub.exe
BINSUFFIX=.exe
WANTZIP=1
else
WANTZIP=0
BINARY=uhub
MAKEARGS="USE_BIGENDIAN=NO"
fi
BINARY=uhub${BINSUFFIX}
if [ "${HOST_SYSTEM}" = "freebsd" ]; then
MAKE=gmake
fi
VERSION=`grep define\ VERSION version.h | cut -f 3 -d " " | tr -d [=\"=]`
SNAPSHOT=`date '+%Y%m%d'`
PACKAGE=uhub-${VERSION}
PACKAGE_SRC=${PACKAGE}-src
PACKAGE_BIN=${PACKAGE}-${HOST_SYSTEM}-${HOST_MACHINE}
URL_ARCHIVE='build-archive:~/uhub/'
URL_PUBLISH='domeneshop:~/www/downloads/uhub/'
URL_SNAPSHOT='domeneshop:~/www/downloads/uhub/snapshots/'
ARCHIVE='build-archive:~/www/downloads/uhub/'
function export_source_directory
{
@@ -51,45 +56,85 @@ function package_zips
gzip -c -9 $1.tar > $1.tar.gz
bzip2 -c -9 $1.tar > $1.tar.bz2
rm -f $1.tar
zip -q -9 -r $1.zip $2
if [ $WANTZIP -eq 1 ]; then
zip -q -9 -r $1.zip $2
fi
}
function export_sources
{
export_source_directory
make autotest.c && cp autotest.c ${PACKAGE}/autotest.c
rm -Rf ${PACKAGE}/admin
if [ ! -d ${PACKAGE} ]; then
export_source_directory
fi
cd ${PACKAGE}
${MAKE} ${MAKEARGS} autotest.c
cd ..
if [ ! -f ${PACKAGE}/autotest.c ]; then
echo "Unable to create autotest.c, aborting..."
exit 1
fi
rm -Rf ${PACKAGE}/admin
package_zips ${PACKAGE_SRC} ${PACKAGE}
rm -Rf ${PACKAGE};
cp ChangeLog ChangeLog-${VERSION}
}
function build_binaries
{
if [ ! -d ${PACKAGE} ]; then
export_source_directory
fi
cd ${PACKAGE}
${MAKE} ${MAKEARGS} RELEASE=YES
cd ..
if [ ! -x ${PACKAGE}/${BINARY} ]; then
echo "Build failed, no binary found..."
exit 1
fi
}
function export_binaries
{
export_source_directory
build_binaries
rm -Rf ${PACKAGE}/admin
rm -Rf ${PACKAGE}/autotest
rm -Rf ${PACKAGE}/src
rm -Rf ${PACKAGE}/debian
rm -f ${PACKAGE}/autotest.c
rm -f ${PACKAGE}/*akefile
rm -f ${PACKAGE}/version.h
rm -f ${PACKAGE}/doc/Doxyfile
rm -f ${PACKAGE}/doc/uhub.dot
make
if [ -x ${BINARY} ]; then
cp ${BINARY} ${PACKAGE}
else
echo "No binary found!"
exit 1
fi
rm -f ${PACKAGE}/libuhub*
package_zips ${PACKAGE_BIN} ${PACKAGE}
rm -Rf ${PACKAGE}
}
rm -Rf ${PACKAGE};
function upload_pkg
{
if [ -f $1 ]; then
scp $1 ${ARCHIVE}
fi
}
function upload_packages
{
upload_pkg ${PACKAGE_SRC}.tar.gz
upload_pkg ${PACKAGE_SRC}.tar.bz2
upload_pkg ${PACKAGE_SRC}.zip
upload_pkg ChangeLog-${VERSION}
upload_pkg ${PACKAGE_BIN}.tar.gz
upload_pkg ${PACKAGE_BIN}.tar.bz2
upload_pkg ${PACKAGE_BIN}.zip
}

3
admin/export.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
. admin/common.sh
export_source_directory

95
admin/make_pkg_deb.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
. admin/common.sh
export_source_directory
build_binaries
DEB_REVISION=1
if [ -d deb ]; then
rm -Rf deb
fi
mkdir -p \
deb/DEBIAN \
deb/usr/bin \
deb/usr/share/man/man1/ \
deb/usr/share/doc/uhub \
deb/etc/uhub \
|| exit 1
find deb -type d | xargs chmod 755
# Copy binaries...
cp ${PACKAGE}/${BINARY} deb/usr/bin
strip deb/usr/bin/${BINARY}
# Copy configuration files...
cp ${PACKAGE}/doc/uhub.conf deb/etc/uhub
cp ${PACKAGE}/doc/users.conf deb/etc/uhub
echo "Welcome to uHub" > deb/etc/uhub/motd.txt
# Copy other files
cp ${PACKAGE}/README deb/usr/share/doc/uhub
cp ${PACKAGE}/AUTHORS deb/usr/share/doc/uhub
gzip -c --best < ${PACKAGE}/ChangeLog > deb/usr/share/doc/uhub/changelog.gz
gzip -c --best < ${PACKAGE}/doc/uhub.1 > deb/usr/share/man/man1/uhub.1.gz
cat > deb/usr/share/doc/uhub/copyright <<EOF
uHub - a high performance hub for the ADC peer-to-peer network
Copyright (C) 2007-2009 Jan Vidar Krey <janvidar@extatic.org>
uHub is free and open source software, licensed under the
GNU General Public License version 3.
For details, see /usr/share/common-licenses/GPL-3
EOF
gzip -c --best > deb/usr/share/doc/uhub/changelog.Debian.gz <<EOF
uhub (${VERSION}) stable; urgency=low
* See changelog.gz for details.
-- Jan Vidar Krey <janvidar@extatic.org> `date -R`
EOF
### Write control files
cd deb
echo "/etc/uhub/uhub.conf" > DEBIAN/conffiles
echo "/etc/uhub/users.conf" >> DEBIAN/conffiles
echo "/etc/uhub/motd.txt" >> DEBIAN/conffiles
md5sum `find usr -type f` > DEBIAN/md5sums
INSTALL_SIZE=`du -s | cut -f 1`
cat > DEBIAN/control <<EOF
Package: uhub
Version: ${VERSION}-${DEB_REVISION}
Architecture: ${HOST_MACHINE}
Maintainer: Jan Vidar Krey <janvidar@extatic.org>
Installed-Size: ${INSTALL_SIZE}
Depends: libc6 (>= 2.7-1), libevent1 (>= 1.3e-1)
Section: net
Priority: optional
Description: a high performance hub for the ADC peer-to-peer network
uHub is a high performance peer-to-peer hub for the ADC network.
Its low memory footprint allows it to handle several thousand users
on high-end servers, or a small private hub on embedded hardware.
.
Homepage: http://www.extatic.org/uhub/
EOF
cd ..
### Create deb file
fakeroot dpkg-deb --build deb
mv deb.deb uhub_${VERSION}-${DEB_REVISION}_${HOST_MACHINE}.deb
### Check for errors
lintian uhub_${VERSION}-${DEB_REVISION}_${HOST_MACHINE}.deb
### Cleanup
rm -Rf deb
rm -Rf ${PACKAGE}

View File

@@ -1,11 +0,0 @@
#!/bin/bash
# set -x
ME=`dirname $0`
. ${ME}/common.sh
# Git Export
export_sources
export_binaries

3
admin/release_binaries.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
. admin/common.sh
export_binaries

4
admin/release_sources.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
. admin/common.sh
WANTZIP=1
export_sources

26
admin/setup_archive.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
PUB="${HOME}/.ssh/id_rsa.pub"
CFG="${HOME}/.ssh/config"
if [ ! "`grep build-archive ${CFG}`" ]; then
echo "Updating ssh config (${CFG})..."
cat >> ${CFG} <<EOF
Host build-archive
ForwardX11 no
HostName login.domeneshop.no
User extatic
EOF
else
echo "ssh config seems OK (${CFG})"
fi
if [ ! -f ${PUB} ]; then
echo "No id_rsa.pub - run ssh-keygen"
exit 1
fi
echo "Copying public key (${PUB})..."
cat ${PUB} | ssh build-archive "cat >> .ssh/authorized_keys"

3
admin/upload.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
. admin/common.sh
upload_packages

View File

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

View File

@@ -5,17 +5,17 @@
#define USER_NICK "Friend"
#define USER_SID "AAAB"
static struct user* inf_user = 0;
static struct hub_user* inf_user = 0;
static struct hub_info* inf_hub = 0;
extern int hub_handle_info_login(struct user* user, struct adc_message* cmd);
extern int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd);
static void inf_create_hub()
{
inf_hub = (struct hub_info*) hub_malloc_zero(sizeof(struct hub_info));
inf_hub->users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
inf_hub->users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
inf_hub->users->list = list_create();
inf_hub->users->free_sid = 1;
inf_hub->users->sids = sid_pool_create(500);
inf_hub->acl = (struct acl_handle*) hub_malloc_zero(sizeof(struct acl_handle));
inf_hub->config = (struct hub_config*) hub_malloc_zero(sizeof(struct hub_config));
@@ -27,16 +27,23 @@ static void inf_create_hub()
static void inf_destroy_hub()
{
/* FIXME */
list_destroy(inf_hub->users->list);
sid_pool_destroy(inf_hub->users->sids);
acl_shutdown(inf_hub->acl);
free_config(inf_hub->config);
hub_free(inf_hub->users);
hub_free(inf_hub->acl);
hub_free(inf_hub->config);
hub_free(inf_hub);
}
static void inf_create_user()
{
if (inf_user) return;
inf_user = (struct user*) hub_malloc_zero(sizeof(struct user));
inf_user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
inf_user->id.sid = 1;
inf_user->sd = -1;
inf_user->hub = inf_hub;
inf_user->net.connection.sd = -1;
inf_user->limits.upload_slots = 1;
}
@@ -55,13 +62,13 @@ EXO_TEST(inf_create_setup,
});
/* FIXME: MEMORY LEAK - Need to fix hub_handle_info_login */
#define CHECK_INF(MSG, EXPECT) \
struct adc_message* msg = adc_msg_parse_verify(inf_user, MSG, strlen(MSG)); \
int ok = hub_handle_info_login(inf_user, msg); \
int ok = hub_handle_info_login(inf_hub, inf_user, msg); /* FIXME: MEMORY LEAK */ \
adc_msg_free(msg); \
if (ok != EXPECT) \
printf("Expected %d, got %d\n", EXPECT, ok); \
if (ok == EXPECT) \
user_set_info(inf_user, 0); \
return ok == EXPECT;
@@ -106,7 +113,7 @@ EXO_TEST(inf_nick_10, {
struct adc_message* msg = adc_msg_parse_verify(inf_user, line, strlen(line));
adc_msg_add_named_argument(msg, "NI", nick);
int ok = hub_handle_info_login(inf_user, msg);
int ok = hub_handle_info_login(inf_hub, inf_user, msg);
adc_msg_free(msg);
if (ok != status_msg_inf_error_nick_not_utf8)
printf("Expected %d, got %d\n", status_msg_inf_error_nick_not_utf8, ok);

View File

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

View File

@@ -1,5 +1,5 @@
#include <uhub.h>
static struct user* g_user = 0;
static struct hub_user* g_user = 0;
static const char* test_string1 = "IINF AAfoo BBbar CCwhat\n";
static const char* test_string2 = "BMSG AAAB Hello\\sWorld!\n";
static const char* test_string3 = "BINF AAAB IDAN7ZMSLIEBL53OPTM7WXGSTXUS3XOY6KQS5LBGX NIFriend DEstuff SL3 SS0 SF0 VEQuickDC/0.4.17 US6430 SUADC0,TCP4,UDP4 I4127.0.0.1 HO5 HN1 AW\n";
@@ -11,12 +11,17 @@ static void create_test_user()
if (g_user)
return;
g_user = (struct user*) malloc(sizeof(struct user));
memset(g_user, 0, sizeof(struct user));
g_user = (struct hub_user*) malloc(sizeof(struct hub_user));
memset(g_user, 0, sizeof(struct hub_user));
memcpy(g_user->id.nick, "exotic-tester", 13);
g_user->id.sid = 1;
}
EXO_TEST(adc_message_first, {
create_test_user();
return g_user != 0;
});
EXO_TEST(adc_message_parse_1, {
struct adc_message* msg = adc_msg_create("IMSG Hello\\sWorld!");
int ok = msg != NULL;
@@ -30,7 +35,6 @@ EXO_TEST(adc_message_parse_2, {
});
EXO_TEST(adc_message_parse_3, {
create_test_user();
struct adc_message* msg = adc_msg_parse_verify(g_user, "BMSG AAAB Hello\\sWorld!", 23);
int ok = msg != NULL;
adc_msg_free(msg);
@@ -144,12 +148,29 @@ EXO_TEST(adc_message_parse_20, {
return ok;
});
EXO_TEST(adc_message_parse_21, {
struct adc_message* msg = adc_msg_parse_verify(g_user, "EMSG AAAC AAAB Hello\\sthere!\n", 29);
return msg == NULL;
});
EXO_TEST(adc_message_parse_22, {
struct adc_message* msg = adc_msg_parse_verify(g_user, "\n", 0);
return msg == NULL;
});
EXO_TEST(adc_message_parse_23, {
struct adc_message* msg = adc_msg_parse_verify(g_user, "\r\n", 1);
return msg == NULL;
});
EXO_TEST(adc_message_parse_24, {
struct adc_message* msg = adc_msg_parse_verify(g_user, "EMSG AAAC\0AAAB Hello\\sthere!\n", 29);
return msg == NULL;
});
EXO_TEST(adc_message_add_arg_1, {
struct adc_message* msg = adc_msg_create(test_string1);
adc_msg_add_argument(msg, "XXwtf?");
@@ -491,13 +512,22 @@ EXO_TEST(adc_message_update_3, {
return updater2 != NULL;
});
extern void update_user_info(struct user* u, struct adc_message* cmd);
EXO_TEST(adc_message_update_4, {
update_user_info(g_user, updater2);
user_update_info(g_user, updater2);
return strlen(g_user->info->cache) == 159;
});
EXO_TEST(adc_message_update_4_cleanup, {
adc_msg_free(updater1);
updater1 = 0;
adc_msg_free(updater2);
updater2 = 0;
adc_msg_free(g_user->info);
g_user->info = 0;
return 1;
});
EXO_TEST(adc_message_empty_1, {
struct adc_message* msg = adc_msg_parse_verify(g_user, test_string2, strlen(test_string2));
int ok = adc_msg_is_empty(msg) == 0;
@@ -519,3 +549,10 @@ EXO_TEST(adc_message_empty_3, {
return ok;
});
EXO_TEST(adc_message_last, {
hub_free(g_user);
g_user = 0;
return g_user == 0;
});

View File

@@ -100,4 +100,12 @@ EXO_TEST(utf8_valid_3, { return is_valid_utf8("0123456789"); });
EXO_TEST(utf8_valid_4, { return is_valid_utf8( (char[]) { 0x65, 0x00} ); });
EXO_TEST(utf8_valid_5, { return !is_valid_utf8( (char[]) { 0xD8, 0x00} ); });
EXO_TEST(utf8_valid_6, { return is_valid_utf8( (char[]) { 0x24, 0x00} ); });
EXO_TEST(utf8_valid_7, { return !is_valid_utf8( (char[]) { 0xC2, 0x24, 0x00} ); });
EXO_TEST(utf8_valid_8, { return is_valid_utf8( (char[]) { 0xC2, 0xA2, 0x00} ); });
EXO_TEST(utf8_valid_9, { return is_valid_utf8( (char[]) { 0xE2, 0x82, 0xAC, 0x00} ); });
EXO_TEST(utf8_valid_10, { return !is_valid_utf8( (char[]) { 0xC2, 0x32, 0x00} ); });
EXO_TEST(utf8_valid_11, { return !is_valid_utf8( (char[]) { 0xE2, 0x82, 0x32, 0x00} ); });
EXO_TEST(utf8_valid_12, { return !is_valid_utf8( (char[]) { 0xE2, 0x32, 0x82, 0x00} ); });

View File

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

5
debian/changelog vendored
View File

@@ -1,5 +0,0 @@
uhub (0.2.6-1) unstable; urgency=low
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
-- Jan Vidar Krey <janvidar@extatic.org> Tue, 17 Mar 2009 00:38:12 +0100

1
debian/compat vendored
View File

@@ -1 +0,0 @@
7

3
debian/conffiles vendored
View File

@@ -1,3 +0,0 @@
etc/uhub/uhub.conf
etc/uhub/users.conf
etc/uhub/motd.txt

15
debian/control vendored
View File

@@ -1,15 +0,0 @@
Source: uhub
Section: net
Priority: extra
Maintainer: Jan Vidar Krey <janvidar@extatic.org>
Build-Depends: debhelper (>= 7)
Standards-Version: 3.8.1
Homepage: http://www.extatic.org/uhub/
Package: uhub
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: uHub is a high performance peer-to-peer hub for the ADC network.
Its low memory footprint allows it to handle several thousand users on high-end servers,
or a small private hub on embedded hardware.
uHub uses the ADC protocol, and is compatible with DC++, jUCy and other ADC clients.

9
debian/copyright vendored
View File

@@ -1,9 +0,0 @@
Copyright:
Copyright (C) 2008-2009 Jan Vidar Krey <janvidar@extatic.org>
License:
Licensed under the GPL version 3,
see `/usr/share/common-licenses/GPL-3'.

1
debian/dirs vendored
View File

@@ -1 +0,0 @@
usr/bin

3
debian/docs vendored
View File

@@ -1,3 +0,0 @@
BUGS
README
AUTHORS

1
debian/files vendored
View File

@@ -1 +0,0 @@
uhub_0.2.6-1_amd64.deb net extra

157
debian/init.d vendored
View File

@@ -1,157 +0,0 @@
#! /bin/sh
#
# skeleton example file to build /etc/init.d/ scripts.
# This file should be used to construct scripts for /etc/init.d.
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
# Further changes by Javier Fernandez-Sanguino <jfs@debian.org>
#
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/uhub
NAME=uhub
DESC=uhub
test -x $DAEMON || exit 0
LOGDIR=/var/log/uhub
PIDFILE=/var/run/$NAME.pid
DODTIME=1 # Time to wait for the server to die, in seconds
# If this value is set too low you might not
# let some servers to die gracefully and
# 'restart' will not work
# Include uhub defaults if available
if [ -f /etc/default/uhub ] ; then
. /etc/default/uhub
fi
set -e
running_pid()
{
# Check if a given process pid's cmdline matches a given name
pid=$1
name=$2
[ -z "$pid" ] && return 1
[ ! -d /proc/$pid ] && return 1
cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
# Is this the expected child?
[ "$cmd" != "$name" ] && return 1
return 0
}
running()
{
# Check if the process is running looking at /proc
# (works for all users)
# No pidfile, probably no daemon present
[ ! -f "$PIDFILE" ] && return 1
# Obtain the pid and check it against the binary name
pid=`cat $PIDFILE`
running_pid $pid $DAEMON || return 1
return 0
}
force_stop() {
# Forcefully kill the process
[ ! -f "$PIDFILE" ] && return
if running ; then
kill -15 $pid
# Is it really dead?
[ -n "$DODTIME" ] && sleep "$DODTIME"s
if running ; then
kill -9 $pid
[ -n "$DODTIME" ] && sleep "$DODTIME"s
if running ; then
echo "Cannot kill $LABEL (pid=$pid)!"
exit 1
fi
fi
fi
rm -f $PIDFILE
return 0
}
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $DAEMON -- $DAEMON_OPTS
if running ; then
echo "$NAME."
else
echo " ERROR."
fi
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--exec $DAEMON
echo "$NAME."
;;
force-stop)
echo -n "Forcefully stopping $DESC: "
force_stop
if ! running ; then
echo "$NAME."
else
echo " ERROR."
fi
;;
reload)
#
# If the daemon can reload its config files on the fly
# for example by sending it SIGHUP, do it here.
#
# If the daemon responds to changes in its config file
# directly anyway, make this a do-nothing entry.
#
echo "Reloading $DESC configuration files."
start-stop-daemon --stop --signal 1 --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON
#;;
force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart" except that it does nothing if the
# daemon isn't already running.
# check wether $DAEMON is running. If so, restart
start-stop-daemon --stop --test --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON \
&& $0 restart \
|| exit 0
;;
restart)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON
[ -n "$DODTIME" ] && sleep $DODTIME
start-stop-daemon --start --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
status)
echo -n "$LABEL is "
if running ; then
echo "running"
else
echo " not running."
exit 1
fi
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2
exit 1
;;
esac
exit 0

39
debian/postinst vendored
View File

@@ -1,39 +0,0 @@
#!/bin/sh
# postinst script for uhub
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

37
debian/postrm vendored
View File

@@ -1,37 +0,0 @@
#!/bin/sh
# postrm script for uhub
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

35
debian/preinst vendored
View File

@@ -1,35 +0,0 @@
#!/bin/sh
# preinst script for uhub
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

38
debian/prerm vendored
View File

@@ -1,38 +0,0 @@
#!/bin/sh
# prerm script for uhub
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

91
debian/rules vendored
View File

@@ -1,91 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
# Add here commands to compile the package.
$(MAKE)
#docbook-to-man debian/uhub.sgml > uhub.1
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
$(MAKE) clean
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
# Add here commands to install the package into debian/uhub.
$(MAKE) DESTDIR=$(CURDIR)/debian/uhub install
# Build architecture-independent files here.
binary-indep: install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: install
dh_testdir
dh_testroot
dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

10
debian/uhub.default vendored
View File

@@ -1,10 +0,0 @@
# Defaults for uhub initscript
# sourced by /etc/init.d/uhub
# installed at /etc/default/uhub by the maintainer scripts
# Additional options that are passed to the Daemon.
ENABLED=1
LOGFILE="/var/log/uhug.log"
USER=nobody
GROUP=nogroup
DAEMON_OPTS="-f -l ${LOGFILE} -u ${USER} -g {GROUP}"

72
doc/uhub.1 Normal file
View File

@@ -0,0 +1,72 @@
.TH UHUB 1 "March 2009"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
uhub \- a high performance ADC peer-to-peer hub
.SH SYNOPSIS
.B uhub
.RI [ options ]
.SH DESCRIPTION
uHub is a high performance peer-to-peer hub for the ADC network.
Its low memory footprint allows it to handle several thousand users
on high-end servers, or a small private hub on embedded hardware.
.SH "OPTIONS"
.TP
.BI \^\-v
Verbose mode, add more -v's for higher verbosity.
.TP
.BI \^\-q
Quiet mode, if quiet mode is enabled no output or logs are made.
.TP
.BI \^\-f
Fork uhub to background in order to run it as a daemon.
.TP
.BI \^\-l " logfile"
Log messages to the given logfile (default: stderr)
.TP
.BI \^\-L
Log messages to syslog.
.TP
.BI \^\-c " config"
Specify configuration file (default: /etc/uhub/uhub.conf)
.TP
.BI \^\-C
Check configuration files and return. Will print either \"OK\" or \"ERROR\".
.TP
.BI \^\-s
Show all configuration parameters. In a format that is compatible with
the configuration files.
.TP
.BI \^\-S
Show all non-default configuration parameters.
.TP
.BI \^\-h
Show the help message.
.TP
.BI \^\-u " user"
Drop privileges and run as the given user.
.TP
.BI \^\-g " group"
Drop privileges and run with the given group permissions.
.TP
.BI \^\-V
Show the version number
.SH EXAMPLES
To run uhub as a daemon, and log to a file:
.TP
.B uhub " -f -l /var/log/uhub/uhub.log"
.SH AUTHOR
This program was written by Jan Vidar Krey <janvidar@extatic.org>
.SH "BUG REPORTS"
If you find a bug in uhub please report it to
.B http://bugs.extatic.org/

View File

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

View File

@@ -34,6 +34,7 @@
struct adc_message* adc_msg_incref(struct adc_message* msg)
{
if (!msg) return 0;
#ifndef ADC_MESSAGE_INCREF
msg->references++;
return msg;
@@ -234,7 +235,7 @@ struct adc_message* adc_msg_copy(const struct adc_message* cmd)
}
struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_t length)
struct adc_message* adc_msg_parse_verify(struct hub_user* u, const char* line, size_t length)
{
struct adc_message* command = adc_msg_parse(line, length);
@@ -243,6 +244,7 @@ struct adc_message* adc_msg_parse_verify(struct user* u, const char* line, size_
if (command->source && (!u || command->source != u->id.sid))
{
LOG_DEBUG("Command does not match user's SID (command->source=%d, user->id.sid=%d)", command->source, (u ? u->id.sid : 0));
adc_msg_free(command);
return 0;
}
@@ -263,6 +265,13 @@ struct adc_message* adc_msg_parse(const char* line, size_t length)
if (command == NULL)
return NULL; /* OOM */
if (!is_printable_utf8(line, length))
{
LOG_DEBUG("Dropped message with non-printable UTF-8 characters.");
hub_free(command);
return NULL;
}
if (line[length-1] != '\n')
{
@@ -511,7 +520,6 @@ int adc_msg_remove_named_argument(struct adc_message* cmd, const char prefix_[2]
{
temp_len = &end[0] - &start[0]; // strlen(start);
/* hub_log(log_trace, " length=%d", (int) (temp_len)); */
endlen = strlen(end);
memmove(start, end, endlen);

View File

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

130
src/adc/sid.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
char* sid_to_string(sid_t sid_)
{
static char t_sid[5];
sid_t sid = (sid_ & 0xFFFFF); /* 20 bits only */
sid_t A, B, C, D = 0;
D = (sid % 32);
sid = (sid - D) / 32;
C = (sid % 32);
sid = (sid - C) / 32;
B = (sid % 32);
sid = (sid - B) / 32;
A = (sid % 32);
t_sid[0] = BASE32_ALPHABET[A];
t_sid[1] = BASE32_ALPHABET[B];
t_sid[2] = BASE32_ALPHABET[C];
t_sid[3] = BASE32_ALPHABET[D];
t_sid[4] = 0;
return t_sid;
}
sid_t string_to_sid(const char* sid)
{
sid_t nsid = 0;
sid_t n, x;
sid_t factors[] = { 32768, 1024, 32, 1};
if (!sid || strlen(sid) != 4) return 0;
for (n = 0; n < 4; n++) {
for (x = 0; x < strlen(BASE32_ALPHABET); x++)
if (sid[n] == BASE32_ALPHABET[x]) break;
if (x == 32) return 0;
nsid += x * factors[n];
}
return nsid;
}
/*
* Session IDs are heavily reused, since they are a fairly scarce
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
* value and 'AAAA' (0) is reserved for the hub.
*
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
*
* When allocating a session ID:
* - If 'count' is less than the pool size (max-min), then allocate within the pool
* - Increase the pool size (see below)
* - If unable to do that, hub is really full - don't let anyone in!
*
* When freeing a session ID:
* - If the session ID being freed is 'max', then decrease the pool size by one.
*
*/
struct sid_pool
{
sid_t min;
sid_t max;
sid_t count;
struct hub_user** map;
};
struct sid_pool* sid_pool_create(sid_t max)
{
struct sid_pool* pool = hub_malloc(sizeof(struct sid_pool));
pool->min = 1;
pool->max = max + 1;
pool->count = 0;
pool->map = hub_malloc_zero(sizeof(struct hub_user*) * pool->max);
pool->map[0] = (struct hub_user*) pool; /* hack to reserve the first sid. */
LOG_DUMP("SID_POOL: max=%d", (int) pool->max);
return pool;
}
void sid_pool_destroy(struct sid_pool* pool)
{
LOG_DUMP("SID_POOL: destroying, current allocs=%d", (int) pool->count);
hub_free(pool->map);
hub_free(pool);
}
sid_t sid_alloc(struct sid_pool* pool, struct hub_user* user)
{
sid_t n = (++pool->count);
for (; (pool->map[n % pool->max]); n++) ;
LOG_DUMP("SID_ALLOC: %d, user=%p", (int) n, user);
pool->map[n] = user;
return n;
}
void sid_free(struct sid_pool* pool, sid_t sid)
{
LOG_DUMP("SID_FREE: %d", (int) sid);
pool->map[sid] = 0;
pool->count--;
}
struct hub_user* sid_lookup(struct sid_pool* pool, sid_t sid)
{
if (!sid || (sid > pool->max))
return 0;
return pool->map[sid];
}

View File

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

View File

@@ -1,193 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
typedef int (*command_handler)(struct user* user, const char* message);
struct commands_handler
{
const char* prefix;
size_t length;
enum user_credentials cred;
command_handler handler;
const char* description;
};
static struct commands_handler command_handlers[];
static void send_message(struct user* user, const char* message)
{
char* buffer = adc_msg_escape(message);
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
adc_msg_add_argument(command, buffer);
route_to_user(user, command);
adc_msg_free(command);
hub_free(buffer);
}
static int command_access_denied(struct user* user, const char* command)
{
char temp[64];
snprintf(temp, 64, "*** Access denied: \"%s\"", command);
send_message(user, temp);
return 0;
}
static int command_stats(struct user* user, const char* message)
{
char temp[128];
snprintf(temp, 128, "*** Stats: %zu users, peak: %zu. Network (up/down): %d/%d KB/s, peak: %d/%d KB/s",
user->hub->users->count,
user->hub->users->count_peak,
(int) user->hub->stats.net_tx / 1024,
(int) user->hub->stats.net_rx / 1024,
(int) user->hub->stats.net_tx_peak / 1024,
(int) user->hub->stats.net_rx_peak / 1024);
send_message(user, temp);
return 0;
}
static int command_help(struct user* user, const char* message)
{
#define MAX_HELP_MSG 1024
size_t n;
char msg[MAX_HELP_MSG];
msg[0] = 0;
strcat(msg, "\n*** Available commands:\n");
for (n = 0; command_handlers[n].prefix; n++)
{
if (command_handlers[n].cred <= user->credentials)
{
strcat(msg, command_handlers[n].prefix);
strcat(msg, " - ");
strcat(msg, command_handlers[n].description);
strcat(msg, "\n");
}
}
send_message(user, msg);
return 0;
}
static int command_uptime(struct user* user, const char* message)
{
char tmp[128];
size_t d;
size_t h;
size_t m;
size_t D = (size_t) difftime(time(0), user->hub->tm_started);
d = D / (24 * 3600);
D = D % (24 * 3600);
h = D / 3600;
D = D % 3600;
m = D / 60;
tmp[0] = 0;
strcat(tmp, "*** Uptime: ");
if (d)
{
strcat(tmp, uhub_itoa((int) d));
strcat(tmp, " day");
if (d != 1) strcat(tmp, "s");
strcat(tmp, ", ");
}
if (h < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) h));
strcat(tmp, ":");
if (m < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) m));
send_message(user, tmp);
return 0;
}
static int command_kick(struct user* user, const char* message)
{
send_message(user, "*** Kick not implemented!");
return 0;
}
static int command_reload(struct user* user, const char* message)
{
send_message(user, "*** Reloading configuration");
user->hub->status = hub_status_restart;
return 0;
}
static int command_shutdown(struct user* user, const char* message)
{
send_message(user, "*** Hub shuting down...");
user->hub->status = hub_status_shutdown;
return 0;
}
static int command_version(struct user* user, const char* message)
{
send_message(user, "*** Powered by " PRODUCT "/" VERSION);
return 0;
}
static int command_myip(struct user* user, const char* message)
{
char tmp[128];
snprintf(tmp, 128, "*** Your IP: %s", ip_convert_to_string(&user->ipaddr));
send_message(user, tmp);
return 0;
}
int command_dipatcher(struct user* user, const char* message)
{
size_t n = 0;
for (n = 0; command_handlers[n].prefix; n++)
{
if (!strncmp(message, command_handlers[n].prefix, command_handlers[n].length))
{
if (command_handlers[n].cred <= user->credentials)
{
return command_handlers[n].handler(user, message);
}
else
{
return command_access_denied(user, &command_handlers[n].prefix[1]);
}
}
}
return 1;
}
static struct commands_handler command_handlers[] = {
{ "!help", 5, cred_guest, command_help, "Show this help message." },
{ "!stats", 6, cred_super, command_stats, "Show hub statistics." },
{ "!version", 8, cred_guest, command_version, "Show hub version info." },
{ "!uptime", 7, cred_guest, command_uptime, "Display hub uptime info." },
{ "!kick", 5, cred_operator, command_kick, "Kick a user" },
{ "!reload", 7, cred_admin, command_reload, "Reload configuration files." },
{ "!shutdown", 9, cred_admin, command_shutdown, "Shutdown hub." },
{ "+myip", 5, cred_guest, command_myip, "Show your own IP." },
{ 0, 0, cred_none, command_help, "{ Last dummy option }" }
};

View File

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

View File

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

551
src/core/commands.c Normal file
View File

@@ -0,0 +1,551 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef DEBUG
#define CRASH_DEBUG
#endif
#define MAX_HELP_MSG 1024
struct hub_command
{
const char* message;
char* prefix;
size_t prefix_len;
struct linked_list* args;
};
typedef int (*command_handler)(struct hub_info* hub, struct hub_user* user, struct hub_command*);
struct commands_handler
{
const char* prefix;
size_t length;
const char* args;
enum user_credentials cred;
command_handler handler;
const char* description;
};
static struct commands_handler command_handlers[];
static void command_destroy(struct hub_command* cmd)
{
if (!cmd) return;
hub_free(cmd->prefix);
if (cmd->args)
{
list_clear(cmd->args, &hub_free);
list_destroy(cmd->args);
}
hub_free(cmd);
}
static struct hub_command* command_create(const char* message)
{
struct hub_command* cmd = hub_malloc_zero(sizeof(struct hub_command));
if (!cmd) return 0;
cmd->message = message;
cmd->args = list_create();
int n = split_string(message, "\\s", cmd->args, 0);
if (n <= 0)
{
command_destroy(cmd);
return 0;
}
char* prefix = list_get_first(cmd->args);
if (prefix[0] && prefix[1])
{
cmd->prefix = hub_strdup(&prefix[1]);
cmd->prefix_len = strlen(cmd->prefix);
}
else
{
command_destroy(cmd);
return 0;
}
list_remove(cmd->args, prefix);
hub_free(prefix);
return cmd;
}
static void send_message(struct hub_info* hub, struct hub_user* user, const char* message)
{
char* buffer = adc_msg_escape(message);
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6);
adc_msg_add_argument(command, buffer);
route_to_user(hub, user, command);
adc_msg_free(command);
hub_free(buffer);
}
static int command_access_denied(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "*** %s: Access denied.", cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "*** %s: Command not found", cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_status_user_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* nick)
{
char temp[128];
snprintf(temp, 128, "*** %s: No user \"%s\"", cmd->prefix, nick);
send_message(hub, user, temp);
return 0;
}
const char* command_get_syntax(struct commands_handler* handler)
{
static char args[128];
args[0] = 0;
size_t n = 0;
if (handler->args)
{
for (n = 0; n < strlen(handler->args); n++)
{
if (n > 0) strcat(args, " ");
switch (handler->args[n])
{
case 'n': strcat(args, "<nick>"); break;
case 'c': strcat(args, "<cid>"); break;
case 'a': strcat(args, "<addr>"); break;
case 'm': strcat(args, "<message>"); break;
}
}
}
return args;
}
static int command_arg_mismatch(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, struct commands_handler* handler)
{
char temp[256];
const char* args = command_get_syntax(handler);
if (args) snprintf(temp, 256, "*** %s: Use: !%s %s", cmd->prefix, cmd->prefix, args);
else snprintf(temp, 256, "*** %s: Use: !%s", cmd->prefix, cmd->prefix);
send_message(hub, user, temp);
return 0;
}
static int command_status(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* message)
{
char temp[1024];
snprintf(temp, 1024, "*** %s: %s", cmd->prefix, message);
send_message(hub, user, temp);
return 0;
}
static int command_stats(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char temp[128];
snprintf(temp, 128, "%zu users, peak: %zu. Network (up/down): %d/%d KB/s, peak: %d/%d KB/s",
hub->users->count,
hub->users->count_peak,
(int) hub->stats.net_tx / 1024,
(int) hub->stats.net_rx / 1024,
(int) hub->stats.net_tx_peak / 1024,
(int) hub->stats.net_rx_peak / 1024);
return command_status(hub, user, cmd, temp);
}
static int command_help(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
size_t n;
char msg[MAX_HELP_MSG];
msg[0] = 0;
strcat(msg, "Available commands:\n");
for (n = 0; command_handlers[n].prefix; n++)
{
if (command_handlers[n].cred <= user->credentials)
{
strcat(msg, "!");
strcat(msg, command_handlers[n].prefix);
strcat(msg, " - ");
strcat(msg, command_handlers[n].description);
strcat(msg, "\n");
}
}
return command_status(hub, user, cmd, msg);
}
static int command_uptime(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
size_t d;
size_t h;
size_t m;
size_t D = (size_t) difftime(time(0), hub->tm_started);
d = D / (24 * 3600);
D = D % (24 * 3600);
h = D / 3600;
D = D % 3600;
m = D / 60;
tmp[0] = 0;
if (d)
{
strcat(tmp, uhub_itoa((int) d));
strcat(tmp, " day");
if (d != 1) strcat(tmp, "s");
strcat(tmp, ", ");
}
if (h < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) h));
strcat(tmp, ":");
if (m < 10) strcat(tmp, "0");
strcat(tmp, uhub_itoa((int) m));
return command_status(hub, user, cmd, tmp);
}
static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
if (target == user)
return command_status(hub, user, cmd, "Cannot kick yourself");
hub_disconnect_user(hub, target, quit_kicked);
return command_status(hub, user, cmd, nick);
}
static int command_ban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
if (target == user)
return command_status(hub, user, cmd, "Cannot kick/ban yourself");
hub_disconnect_user(hub, target, quit_kicked);
acl_user_ban_nick(hub->acl, target->id.nick);
acl_user_ban_cid(hub->acl, target->id.cid);
return command_status(hub, user, cmd, nick);
}
static int command_unban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
return command_status(hub, user, cmd, "Not implemented");
}
static int command_reload(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
hub->status = hub_status_restart;
return command_status(hub, user, cmd, "Reloading configuration...");
}
static int command_shutdown(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
hub->status = hub_status_shutdown;
return command_status(hub, user, cmd, "Hub shutting down...");
}
static int command_version(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
return command_status(hub, user, cmd, "Powered by " PRODUCT "/" VERSION);
}
static int command_myip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
snprintf(tmp, 128, "Your address is \"%s\"", ip_convert_to_string(&user->net.ipaddr));
return command_status(hub, user, cmd, tmp);
}
static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char tmp[128];
char* nick = list_get_first(cmd->args);
struct hub_user* target = uman_get_user_by_nick(hub, nick);
if (!target)
return command_status_user_not_found(hub, user, cmd, nick);
snprintf(tmp, 128, "%s has address \"%s\"", nick, ip_convert_to_string(&target->net.ipaddr));
return command_status(hub, user, cmd, tmp);
}
static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* address = list_get_first(cmd->args);
struct ip_range range;
struct linked_list* users;
struct hub_user* u;
int ret = 0;
ret = ip_convert_address_to_range(address, &range);
if (!ret)
return command_status(hub, user, cmd, "Invalid IP address/range/mask");
users = (struct linked_list*) list_create();
ret = uman_get_user_by_addr(hub, users, &range);
if (!ret)
{
list_destroy(users);
return command_status(hub, user, cmd, "No users found.");
}
char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d match%s:", cmd->prefix, (int) ret, ((ret != 1) ? "es" : ""));
char* buffer = hub_malloc(((MAX_NICK_LEN + INET6_ADDRSTRLEN + 5) * ret) + strlen(tmp) + 3);
buffer[0] = 0;
strcat(buffer, tmp);
strcat(buffer, "\n");
u = (struct hub_user*) list_get_first(users);
while (u)
{
strcat(buffer, u->id.nick);
strcat(buffer, " (");
strcat(buffer, ip_convert_to_string(&u->net.ipaddr));
strcat(buffer, ")\n");
u = (struct hub_user*) list_get_next(users);
}
strcat(buffer, "\n");
send_message(hub, user, buffer);
hub_free(buffer);
return 0;
}
static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen((cmd->message + 10)) + 6);
adc_msg_add_argument(command, (cmd->message + 10));
route_to_all(hub, command);
adc_msg_free(command);
return 0;
}
static int command_history(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
char* buffer;
struct linked_list* messages = hub->chat_history;
char* message = 0;
int ret = (int) list_size(messages);
size_t bufsize;
if (!ret)
{
return command_status(hub, user, cmd, "No messages.");
}
char tmp[128];
snprintf(tmp, 128, "*** %s: Found %d message%s:", cmd->prefix, (int) ret, ((ret != 1) ? "s" : ""));
bufsize = strlen(tmp);
message = (char*) list_get_first(messages);
while (message)
{
bufsize += strlen(message);
message = (char*) list_get_next(messages);
}
buffer = hub_malloc(bufsize+4);
if (!buffer)
{
return command_status(hub, user, cmd, "Not enough memory.");
}
buffer[0] = 0;
strcat(buffer, tmp);
strcat(buffer, "\n");
message = (char*) list_get_first(messages);
while (message)
{
strcat(buffer, message);
message = (char*) list_get_next(messages);
}
strcat(buffer, "\n");
send_message(hub, user, buffer);
hub_free(buffer);
return 0;
}
static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
struct linked_list* messages = hub->logout_info;
struct hub_logout_info* log;
char tmp[1024];
char* search = 0;
size_t search_len = 0;
size_t search_hits = 0;
if (!list_size(messages))
{
return command_status(hub, user, cmd, "No entries logged.");
}
search = list_get_first(cmd->args);
if (search)
{
search_len = strlen(search);
}
if (search_len)
{
sprintf(tmp, "Logged entries: %d, searching for \"%s\"", (int) list_size(messages), search);
}
else
{
sprintf(tmp, "Logged entries: %d", (int) list_size(messages));
}
command_status(hub, user, cmd, tmp);
log = (struct hub_logout_info*) list_get_first(messages);
while (log)
{
const char* address = ip_convert_to_string(&log->addr);
int show = 0;
if (search_len)
{
if (memmem(log->cid, MAX_CID_LEN, search, search_len) || memmem(log->nick, MAX_NICK_LEN, search, search_len) || memmem(address, strlen(address), search, search_len))
{
search_hits++;
show = 1;
}
}
else
{
show = 1;
}
if (show)
{
sprintf(tmp, "* %s %s, %s [%s] - %s", get_timestamp(log->time), log->cid, log->nick, ip_convert_to_string(&log->addr), user_get_quit_reason_string(log->reason));
send_message(hub, user, tmp);
}
log = (struct hub_logout_info*) list_get_next(messages);
}
if (search_len)
{
sprintf(tmp, "%d entries shown.", (int) search_hits);
command_status(hub, user, cmd, tmp);
}
return 0;
}
#ifdef CRASH_DEBUG
static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd)
{
void (*crash)(void) = NULL;
crash();
return 0;
}
#endif
int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message)
{
size_t n = 0;
int rc;
/* Parse and validate the command */
struct hub_command* cmd = command_create(message);
if (!cmd) return 1;
for (n = 0; command_handlers[n].prefix; n++)
{
struct commands_handler* handler = &command_handlers[n];
if (cmd->prefix_len != handler->length)
continue;
if (!strncmp(cmd->prefix, handler->prefix, handler->length))
{
if (handler->cred <= user->credentials)
{
if (!handler->args || (handler->args && list_size(cmd->args) >= strlen(handler->args)))
{
rc = handler->handler(hub, user, cmd);
}
else
{
rc = command_arg_mismatch(hub, user, cmd, handler);
}
command_destroy(cmd);
return rc;
}
else
{
rc = command_access_denied(hub, user, cmd);
command_destroy(cmd);
return rc;
}
}
}
command_not_found(hub, user, cmd);
command_destroy(cmd);
return 1;
}
static struct commands_handler command_handlers[] = {
{ "help", 4, 0, cred_guest, command_help, "Show this help message." },
{ "stats", 5, 0, cred_super, command_stats, "Show hub statistics." },
{ "version", 7, 0, cred_guest, command_version, "Show hub version info." },
{ "history", 7, 0, cred_guest, command_history, "Show the last chat messages." },
{ "uptime", 6, 0, cred_guest, command_uptime, "Display hub uptime info." },
{ "kick", 4, "n", cred_operator, command_kick, "Kick a user" },
{ "ban", 3, "n", cred_operator, command_ban, "Ban a user" },
{ "unban", 5, "n", cred_operator, command_unban, "Lift ban on a user" },
{ "reload", 6, 0, cred_admin, command_reload, "Reload configuration files." },
{ "shutdown", 8, 0, cred_admin, command_shutdown, "Shutdown hub." },
{ "myip", 4, 0, cred_guest, command_myip, "Show your own IP." },
{ "getip", 5, "n", cred_operator, command_getip, "Show IP address for a user" },
{ "whoip", 5, "a", cred_operator, command_whoip, "Show users matching IP range" },
{ "broadcast", 9, "m", cred_operator, command_broadcast,"Send a message to all users" },
{ "log", 3, 0, cred_operator, command_log, "Display log" },
#ifdef CRASH_DEBUG
{ "crash", 5, 0, cred_admin, command_crash, "Crash the hub (DEBUG)." },
#endif
{ 0, 0, 0, cred_none, command_help, "" }
};

View File

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

View File

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

View File

@@ -38,7 +38,10 @@ struct hub_config
int max_send_buffer; /**<<< "Max send buffer before disconnect, per user (default: 128K)" */
int max_send_buffer_soft; /**<<< "Max send buffer before message drops, per user (default: 96K)" */
int low_bandwidth_mode; /**<<< "If this is enabled, the hub will strip off elements from each user's info message to reduce bandwidth usage" */
int max_chat_history; /**<<< "Number of chat messages kept in history (default: 20)" */
int max_logout_log; /**<<< "Number of log entries for people leaving the hub. (default: 100) */
/* Limits enforced on users */
int limit_max_hubs_user; /**<<< "Max concurrent hubs as a user. (0=off, default: 10)" */
int limit_max_hubs_reg; /**<<< "Max concurrent hubs as registered user. (0=off, default: 10)" */
@@ -51,7 +54,7 @@ struct hub_config
int limit_max_share; /**<<< "Limit maximum share size in megabytes (MiB) (0=off, default: 0)" */
int limit_min_slots; /**<<< "Limit minimum number of slots open per user (0=off, default: 0)" */
int limit_max_slots; /**<<< "Limit maximum number of slots open per user (0=off, default: 0)" */
/* Messages that can be sent to a user */
char* msg_hub_full; /**<<< "hub is full" */
char* msg_hub_disabled; /**<<< "hub is disabled" */

View File

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

View File

@@ -19,30 +19,26 @@
#include "uhub.h"
int hub_handle_message(struct user* u, const char* line, size_t length)
struct hub_info* g_hub = 0;
int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* line, size_t length)
{
int ret = 0;
struct adc_message* cmd = 0;
#ifdef NETWORK_DUMP_DEBUG
hub_log(log_protocol, "recv %s: %s", sid_to_string(u->id.sid), line);
#endif
LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);
if (user_is_disconnecting(u))
return -1;
cmd = adc_msg_parse_verify(u, line, length);
if (cmd)
{
switch (cmd->cmd)
{
case ADC_CMD_HSUP: ret = hub_handle_support(u, cmd); break;
case ADC_CMD_HPAS: ret = hub_handle_password(u, cmd); break;
case ADC_CMD_BINF: ret = hub_handle_info(u, cmd); break;
#ifdef ADC_UDP_OPERATION
case ADC_CMD_HCHK: ret = hub_handle_autocheck(u, cmd); break;
#endif
case ADC_CMD_HSUP: ret = hub_handle_support(hub, u, cmd); break;
case ADC_CMD_HPAS: ret = hub_handle_password(hub, u, cmd); break;
case ADC_CMD_BINF: ret = hub_handle_info(hub, u, cmd); break;
case ADC_CMD_DINF:
case ADC_CMD_EINF:
case ADC_CMD_FINF:
@@ -54,7 +50,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
case ADC_CMD_DMSG:
case ADC_CMD_BMSG:
case ADC_CMD_FMSG:
ret = hub_handle_chat_message(u, cmd);
ret = hub_handle_chat_message(hub, u, cmd);
break;
case ADC_CMD_BSCH:
@@ -65,7 +61,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
case ADC_CMD_DRCM:
case ADC_CMD_DCTM:
cmd->priority = -1;
if (u->hub->config->chat_only && u->credentials < cred_operator)
if (hub->config->chat_only && u->credentials < cred_operator)
{
/* These below aren't allowed in chat only hubs */
break;
@@ -74,7 +70,7 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
default:
if (user_is_logged_in(u))
{
ret = route_message(u, cmd);
ret = route_message(hub, u, cmd);
}
else
{
@@ -96,17 +92,16 @@ int hub_handle_message(struct user* u, const char* line, size_t length)
}
int hub_handle_support(struct user* u, struct adc_message* cmd)
int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
{
int ret = 0;
int index = 0;
int ok = 1;
char* arg = adc_msg_get_argument(cmd, index);
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
if (u->hub->status == hub_status_disabled && u->state == state_protocol)
if (hub->status == hub_status_disabled && u->state == state_protocol)
{
on_login_failure(u, status_msg_hub_disabled);
on_login_failure(hub, u, status_msg_hub_disabled);
return -1;
}
@@ -145,14 +140,13 @@ int hub_handle_support(struct user* u, struct adc_message* cmd)
if (ok)
{
hub_send_handshake(u);
if (u->ev_read)
event_add(u->ev_read, &timeout);
hub_send_handshake(hub, u);
user_set_timeout(u, TIMEOUT_HANDSHAKE);
}
else
{
/* disconnect user. Do not send crap during initial handshake! */
user_disconnect(u, quit_logon_error);
hub_disconnect_user(hub, u, quit_logon_error);
ret = -1;
}
}
@@ -161,20 +155,20 @@ int hub_handle_support(struct user* u, struct adc_message* cmd)
}
int hub_handle_password(struct user* u, struct adc_message* cmd)
int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
{
char* password = adc_msg_get_argument(cmd, 0);
int ret = 0;
if (u->state == state_verify)
{
if (password_verify(u, password))
if (acl_password_verify(hub->acl, u, password))
{
on_login_success(u);
on_login_success(hub, u);
}
else
{
on_login_failure(u, status_msg_auth_invalid_password);
on_login_failure(hub, u, status_msg_auth_invalid_password);
ret = -1;
}
}
@@ -184,97 +178,80 @@ int hub_handle_password(struct user* u, struct adc_message* cmd)
}
int hub_handle_chat_message(struct user* u, struct adc_message* cmd)
int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
{
char* message = adc_msg_get_argument(cmd, 0);
int ret = 0;
int relay = 1;
/* TODO: Check for hub-commands here. Set relay to 0 and the message will not be sent to other users. */
if (message[0] == '!' || message[0] == '+')
{
relay = command_dipatcher(u, message);
relay = command_dipatcher(hub, u, message);
}
if (hub->config->chat_is_privileged && !user_is_protected(u) && (cmd->cache[0] == 'B' || cmd->cache[0] == 'F'))
{
relay = 0;
}
if (relay && user_is_logged_in(u))
{
/* adc_msg_remove_named_argument(cmd, "PM"); */
ret = route_message(u, cmd);
if (cmd->cache[0] == 'B')
hub_chat_history_add(hub, u, cmd);
ret = route_message(hub, u, cmd);
}
free(message);
hub_free(message);
return ret;
}
int on_kick(struct user* u, struct adc_message* cmd)
void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
hub_log(log_error, "on_kick() not implemented");
return -1;
}
#ifdef ADC_UDP_OPERATION
int hub_handle_autocheck(struct user* u, struct adc_message* cmd)
{
char* port_str = adc_msg_get_argument(cmd, 0);
char* token = adc_msg_get_argument(cmd, 1);
int port = 0;
if (!port_str || !token || strlen(token) != 4)
char* msg_esc = adc_msg_get_argument(cmd, 0);
char* message = adc_msg_unescape(msg_esc);
char* log = hub_malloc(strlen(message) + strlen(user->id.nick) + 14);
sprintf(log, "%s <%s> %s\n", get_timestamp(time(NULL)), user->id.nick, message);
list_append(hub->chat_history, log);
while (list_size(hub->chat_history) > (size_t) hub->config->max_chat_history)
{
hub_free(port_str);
hub_free(token);
return -1;
char* msg = list_get_first(hub->chat_history);
list_remove(hub->chat_history, msg);
hub_free(msg);
}
port = uhub_atoi(port_str);
if (port == 0 || port > 65535)
{
hub_free(port_str);
hub_free(token);
return -1;
}
hub_send_autocheck(u, port, token);
hub_free(port_str);
hub_free(token);
return 0;
hub_free(message);
hub_free(msg_esc);
}
#endif
void hub_send_autocheck(struct user* u, uint16_t port, const char* token)
void hub_chat_history_clear(struct hub_info* hub)
{
list_clear(hub->chat_history, &hub_free);
}
void hub_send_support(struct user* u)
void hub_send_support(struct hub_info* hub, struct hub_user* u)
{
if (user_is_connecting(u) || user_is_logged_in(u))
{
route_to_user(u, u->hub->command_support);
route_to_user(hub, u, hub->command_support);
}
}
void hub_send_sid(struct user* u)
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
{
sid_t sid;
struct adc_message* command;
if (user_is_connecting(u))
{
command = adc_msg_construct(ADC_CMD_ISID, 10);
u->id.sid = user_manager_get_free_sid(u->hub);
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
route_to_user(u, command);
sid = uman_get_free_sid(hub, u);
adc_msg_add_argument(command, (const char*) sid_to_string(sid));
route_to_user(hub, u, command);
adc_msg_free(command);
}
}
void hub_send_ping(struct user* user)
void hub_send_ping(struct hub_info* hub, struct hub_user* user)
{
/* This will just send a newline, despite appearing to do more below. */
struct adc_message* ping = adc_msg_construct(0, 0);
@@ -282,14 +259,14 @@ void hub_send_ping(struct user* user)
ping->cache[1] = 0;
ping->length = 1;
ping->priority = 1;
route_to_user(user, ping);
route_to_user(hub, user, ping);
adc_msg_free(ping);
}
void hub_send_hubinfo(struct user* u)
void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
{
struct adc_message* info = adc_msg_copy(u->hub->command_info);
struct adc_message* info = adc_msg_copy(hub->command_info);
int value = 0;
if (user_flag_get(u, feature_ping))
@@ -301,66 +278,65 @@ void hub_send_hubinfo(struct user* u)
NE - Hub Network
OW - Hub Owner name
*/
adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(u->hub)));
adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(u->hub)));
adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(u->hub)));
adc_msg_add_named_argument(info, "SF", uhub_itoa(hub_get_shared_files(u->hub)));
adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(hub)));
adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(hub)));
adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(hub)));
adc_msg_add_named_argument(info, "SF", uhub_itoa(hub_get_shared_files(hub)));
/* Maximum/minimum share size */
value = hub_get_max_share(u->hub);
value = hub_get_max_share(hub);
if (value) adc_msg_add_named_argument(info, "XS", uhub_itoa(value));
value = hub_get_min_share(u->hub);
value = hub_get_min_share(hub);
if (value) adc_msg_add_named_argument(info, "MS", uhub_itoa(value));
/* Maximum/minimum upload slots allowed per user */
value = hub_get_max_slots(u->hub);
value = hub_get_max_slots(hub);
if (value) adc_msg_add_named_argument(info, "XL", uhub_itoa(value));
value = hub_get_min_slots(u->hub);
value = hub_get_min_slots(hub);
if (value) adc_msg_add_named_argument(info, "ML", uhub_itoa(value));
/* guest users must be on min/max hubs */
value = hub_get_max_hubs_user(u->hub);
value = hub_get_max_hubs_user(hub);
if (value) adc_msg_add_named_argument(info, "XU", uhub_itoa(value));
value = hub_get_min_hubs_user(u->hub);
value = hub_get_min_hubs_user(hub);
if (value) adc_msg_add_named_argument(info, "MU", uhub_itoa(value));
/* registered users must be on min/max hubs */
value = hub_get_max_hubs_reg(u->hub);
value = hub_get_max_hubs_reg(hub);
if (value) adc_msg_add_named_argument(info, "XR", uhub_itoa(value));
value = hub_get_min_hubs_reg(u->hub);
value = hub_get_min_hubs_reg(hub);
if (value) adc_msg_add_named_argument(info, "MR", uhub_itoa(value));
/* operators must be on min/max hubs */
value = hub_get_max_hubs_op(u->hub);
value = hub_get_max_hubs_op(hub);
if (value) adc_msg_add_named_argument(info, "XO", uhub_itoa(value));
value = hub_get_min_hubs_op(u->hub);
value = hub_get_min_hubs_op(hub);
if (value) adc_msg_add_named_argument(info, "MO", uhub_itoa(value));
/* uptime in seconds */
adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), u->hub->tm_started)));
adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), hub->tm_started)));
}
if (user_is_connecting(u) || user_is_logged_in(u))
{
route_to_user(u, info);
route_to_user(hub, u, info);
}
adc_msg_free(info);
/* Only send banner when connecting */
if (u->hub->config->show_banner && user_is_connecting(u))
if (hub->config->show_banner && user_is_connecting(u))
{
route_to_user(u, u->hub->command_banner);
route_to_user(hub, u, hub->command_banner);
}
}
void hub_send_handshake(struct user* u)
void hub_send_handshake(struct hub_info* hub, struct hub_user* u)
{
hub_send_support(u);
hub_send_sid(u);
hub_send_hubinfo(u);
user_flag_set(u, flag_pipeline);
hub_send_support(hub, u);
hub_send_sid(hub, u);
hub_send_hubinfo(hub, u);
route_flush_pipeline(hub, u);
if (!user_is_disconnecting(u))
{
@@ -368,64 +344,60 @@ void hub_send_handshake(struct user* u)
}
}
void hub_send_motd(struct user* u)
void hub_send_motd(struct hub_info* hub, struct hub_user* u)
{
if (u->hub->command_motd)
if (hub->command_motd)
{
route_to_user(u, u->hub->command_motd);
route_to_user(hub, u, hub->command_motd);
}
}
void hub_send_password_challenge(struct user* u)
void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
{
struct adc_message* igpa;
igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
adc_msg_add_argument(igpa, password_generate_challenge(u));
adc_msg_add_argument(igpa, acl_password_generate_challenge(hub->acl, u));
user_set_state(u, state_verify);
route_to_user(u, igpa);
route_to_user(hub, u, igpa);
adc_msg_free(igpa);
}
static void hub_event_dispatcher(void* callback_data, struct event_data* message)
{
/*
struct hub_info* hub = (struct hub_info*) callback_data;
hub_log(log_trace, "hub_event_dispatcher: %x (ptr=%p)", message->id, message->ptr);
*/
struct hub_user* user = (struct hub_user*) message->ptr;
assert(hub != NULL);
switch (message->id)
{
case UHUB_EVENT_USER_JOIN:
{
if (user_is_disconnecting((struct user*) message->ptr))
if (user_is_disconnecting(user))
break;
if (message->flags)
{
hub_send_password_challenge((struct user*) message->ptr);
hub_send_password_challenge(hub, user);
}
else
{
on_login_success((struct user*) message->ptr);
on_login_success(hub, user);
}
break;
}
case UHUB_EVENT_USER_QUIT:
{
user_manager_remove((struct user*) message->ptr);
send_quit_message((struct user*) message->ptr);
on_logout_user((struct user*) message->ptr);
user_schedule_destroy((struct user*) message->ptr);
uman_remove(hub, user);
uman_send_quit_message(hub, user);
on_logout_user(hub, user);
hub_schedule_destroy_user(hub, user);
break;
}
case UHUB_EVENT_USER_DESTROY:
{
hub_log(log_trace, "hub_event_dispatcher: UHUB_EVENT_USER_DESTROY (ptr=%p)", message->ptr);
user_destroy((struct user*) message->ptr);
user_destroy(user);
break;
}
@@ -439,18 +411,15 @@ static void hub_event_dispatcher(void* callback_data, struct event_data* message
struct hub_info* hub_start_service(struct hub_config* config)
{
struct hub_info* hub = 0;
int server_tcp, ret, ipv6_supported, af;
#ifdef ADC_UDP_OPERATION
int server_udp;
#endif
struct sockaddr_storage addr;
socklen_t sockaddr_size;
int server_tcp, ret, ipv6_supported, af;
char address_buf[INET6_ADDRSTRLEN+1];
hub = hub_malloc_zero(sizeof(struct hub_info));
if (!hub)
{
hub_log(log_fatal, "Unable to allocate memory for hub");
LOG_FATAL("Unable to allocate memory for hub");
return 0;
}
@@ -459,9 +428,9 @@ struct hub_info* hub_start_service(struct hub_config* config)
ipv6_supported = net_is_ipv6_supported();
if (ipv6_supported)
hub_log(log_debug, "IPv6 supported.");
LOG_DEBUG("IPv6 supported.");
else
hub_log(log_debug, "IPv6 not supported.");
LOG_DEBUG("IPv6 not supported.");
if (ip_convert_address(config->server_bind_addr, config->server_port, (struct sockaddr*) &addr, &sockaddr_size) == -1)
{
@@ -486,12 +455,13 @@ struct hub_info* hub_start_service(struct hub_config* config)
#endif
if (!hub->evbase)
{
hub_log(log_error, "Unable to initialize libevent.");
LOG_ERROR("Unable to initialize libevent.");
hub_free(hub);
return 0;
}
hub_log(log_info, "Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
LOG_INFO("Starting " PRODUCT "/" VERSION ", listening on %s:%d...", address_buf, config->server_port);
LOG_DEBUG("Using libevent %s, backend: %s", event_get_version(), event_get_method());
server_tcp = net_socket_create(af, SOCK_STREAM, IPPROTO_TCP);
if (server_tcp == -1)
@@ -501,119 +471,52 @@ struct hub_info* hub_start_service(struct hub_config* config)
return 0;
}
#ifdef ADC_UDP_OPERATION
server_udp = net_socket_create(af, SOCK_DGRAM, IPPROTO_UDP);
if (server_udp == -1)
{
event_base_free(hub->evbase);
hub_free(hub);
return 0;
}
#endif
ret = net_set_reuseaddress(server_tcp, 1);
if (ret == -1)
{
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
#ifdef ADC_UDP_OPERATION
ret = net_set_reuseaddress(server_udp, 1);
if (ret == -1)
{
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
net_close(server_udp);
return 0;
}
#endif
ret = net_set_nonblocking(server_tcp, 1);
if (ret == -1)
{
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
#ifdef ADC_UDP_OPERATION
ret = net_set_nonblocking(server_udp, 1);
if (ret == -1)
{
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
net_close(server_udp);
return 0;
}
#endif
ret = net_bind(server_tcp, (struct sockaddr*) &addr, sockaddr_size);
if (ret == -1)
{
hub_log(log_fatal, "hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
LOG_FATAL("hub_start_service(): Unable to bind to TCP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
#ifdef ADC_UDP_OPERATION
ret = net_bind(server_udp, (struct sockaddr*) &addr, sockaddr_size);
if (ret == -1)
{
hub_log(log_fatal, "hub_start_service(): Unable to bind to UDP local address. errno=%d, str=%s", net_error(), net_error_string(net_error()));
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
net_close(server_udp);
return 0;
}
#endif
ret = net_listen(server_tcp, SERVER_BACKLOG);
if (ret == -1)
{
hub_log(log_fatal, "hub_start_service(): Unable to listen to socket");
LOG_FATAL("hub_start_service(): Unable to listen to socket");
event_base_free(hub->evbase);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
hub->fd_tcp = server_tcp;
#ifdef ADC_UDP_OPERATION
hub->fd_udp = server_udp;
#endif
hub->config = config;
hub->users = NULL;
if (user_manager_init(hub) == -1)
if (uman_init(hub) == -1)
{
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
@@ -621,61 +524,72 @@ struct hub_info* hub_start_service(struct hub_config* config)
event_base_set(hub->evbase, &hub->ev_accept);
if (event_add(&hub->ev_accept, NULL) == -1)
{
user_manager_shutdown(hub);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
#ifdef ADC_UDP_OPERATION
event_set(&hub->ev_datagram, hub->fd_udp, EV_READ | EV_PERSIST, net_on_packet, hub);
event_base_set(hub->evbase, &hub->ev_datagram);
if (event_add(&hub->ev_datagram, NULL) == -1)
{
user_manager_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
net_close(server_udp);
return 0;
}
#endif
if (event_queue_initialize(&hub->queue, hub_event_dispatcher, (void*) hub) == -1)
{
user_manager_shutdown(hub);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
#ifdef ADC_UDP_OPERATION
net_close(server_udp);
#endif
return 0;
}
hub->recvbuf = hub_malloc(MAX_RECV_BUF);
hub->sendbuf = hub_malloc(MAX_SEND_BUF);
if (!hub->recvbuf || !hub->sendbuf)
{
hub_free(hub->recvbuf);
hub_free(hub->sendbuf);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
return 0;
}
hub->chat_history = (struct linked_list*) list_create();
hub->logout_info = (struct linked_list*) list_create();
if (!hub->chat_history)
{
list_destroy(hub->chat_history);
list_destroy(hub->logout_info);
hub_free(hub->recvbuf);
hub_free(hub->sendbuf);
uman_shutdown(hub);
hub_free(hub);
net_close(server_tcp);
return 0;
}
hub->status = hub_status_running;
g_hub = hub;
return hub;
}
void hub_shutdown_service(struct hub_info* hub)
{
hub_log(log_trace, "hub_shutdown_service()");
LOG_TRACE("hub_shutdown_service()");
event_queue_shutdown(hub->queue);
event_del(&hub->ev_accept);
#ifdef ADC_UDP_OPERATION
event_del(&hub->ev_datagram);
net_close(hub->fd_udp);
#endif
net_close(hub->fd_tcp);
user_manager_shutdown(hub);
uman_shutdown(hub);
hub->status = hub_status_stopped;
event_base_free(hub->evbase);
hub_free(hub->sendbuf);
hub_free(hub->recvbuf);
hub_chat_history_clear(hub);
list_destroy(hub->chat_history);
list_clear(hub->logout_info, &hub_free);
list_destroy(hub->logout_info);
hub_free(hub);
hub = 0;
g_hub = 0;
}
#define SERVER "" PRODUCT "/" VERSION ""
@@ -685,14 +599,14 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
int fd, ret;
char buf[MAX_RECV_BUF];
char* tmp;
char* server = adc_msg_escape(SERVER); /* FIXME: OOM */
hub->acl = acl;
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15 + strlen(SERVER));
hub->command_info = adc_msg_construct(ADC_CMD_IINF, 15 + strlen(server));
if (hub->command_info)
{
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_CLIENT_TYPE, ADC_CLIENT_TYPE_HUB);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, SERVER);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_USER_AGENT, server);
tmp = adc_msg_escape(hub->config->hub_name);
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_NICK, tmp);
@@ -730,13 +644,17 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
adc_msg_add_argument(hub->command_support, ADC_PROTO_SUPPORT);
}
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(SERVER));
hub->command_banner = adc_msg_construct(ADC_CMD_ISTA, 25 + strlen(server));
if (hub->command_banner)
{
adc_msg_add_argument(hub->command_banner, "000 Powered\\sby\\s" SERVER);
tmp = adc_msg_escape("Powered by " SERVER);
adc_msg_add_argument(hub->command_banner, "000");
adc_msg_add_argument(hub->command_banner, tmp);
hub_free(tmp);
}
hub->status = (hub->config->hub_enabled ? hub_status_running : hub_status_disabled);
hub_free(server);
}
@@ -757,7 +675,7 @@ void hub_free_variables(struct hub_info* hub)
*/
static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
{
struct user* lookup = get_user_by_nick(hub, nick);
struct hub_user* lookup = uman_get_user_by_nick(hub, nick);
if (lookup)
{
return 1;
@@ -771,7 +689,7 @@ static inline int is_nick_in_use(struct hub_info* hub, const char* nick)
*/
static inline int is_cid_in_use(struct hub_info* hub, const char* cid)
{
struct user* lookup = get_user_by_cid(hub, cid);
struct hub_user* lookup = uman_get_user_by_cid(hub, cid);
if (lookup)
{
return 1;
@@ -796,9 +714,9 @@ static void set_status_code(enum msg_status_level level, int code, char buffer[4
* @param msg See enum status_message
* @param level See enum status_level
*/
void hub_send_status(struct user* user, enum status_message msg, enum msg_status_level level)
void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_message msg, enum msg_status_level level)
{
struct hub_config* cfg = user->hub->config;
struct hub_config* cfg = hub->config;
struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
if (!cmd) return;
char code[4];
@@ -853,7 +771,7 @@ void hub_send_status(struct user* user, enum status_message msg, enum msg_status
adc_msg_add_argument(cmd, flag);
}
route_to_user(user, cmd);
route_to_user(hub, user, cmd);
adc_msg_free(cmd);
}
@@ -898,6 +816,46 @@ const char* hub_get_status_message(struct hub_info* hub, enum status_message msg
return "Unknown";
}
const char* hub_get_status_message_log(struct hub_info* hub, enum status_message msg)
{
#define STATUS(MSG) case status_ ## MSG : return #MSG; break
switch (msg)
{
STATUS(msg_hub_full);
STATUS(msg_hub_disabled);
STATUS(msg_hub_registered_users_only);
STATUS(msg_inf_error_nick_missing);
STATUS(msg_inf_error_nick_multiple);
STATUS(msg_inf_error_nick_invalid);
STATUS(msg_inf_error_nick_long);
STATUS(msg_inf_error_nick_short);
STATUS(msg_inf_error_nick_spaces);
STATUS(msg_inf_error_nick_bad_chars);
STATUS(msg_inf_error_nick_not_utf8);
STATUS(msg_inf_error_nick_taken);
STATUS(msg_inf_error_nick_restricted);
STATUS(msg_inf_error_cid_invalid);
STATUS(msg_inf_error_cid_missing);
STATUS(msg_inf_error_cid_taken);
STATUS(msg_inf_error_pid_missing);
STATUS(msg_inf_error_pid_invalid);
STATUS(msg_ban_permanently);
STATUS(msg_ban_temporarily);
STATUS(msg_auth_invalid_password);
STATUS(msg_auth_user_not_found);
STATUS(msg_error_no_memory);
STATUS(msg_user_share_size_low);
STATUS(msg_user_share_size_high);
STATUS(msg_user_slots_low);
STATUS(msg_user_slots_high);
STATUS(msg_user_hub_limit_low);
STATUS(msg_user_hub_limit_high);
}
#undef STATUS
return "unknown";
}
size_t hub_get_user_count(struct hub_info* hub)
{
return hub->users->count;
@@ -976,17 +934,87 @@ size_t hub_get_min_hubs_op(struct hub_info* hub)
void hub_event_loop(struct hub_info* hub)
{
#if 0
event_dispatch();
#endif
int ret;
do
{
ret = event_base_loop(hub->evbase, EVLOOP_ONCE);
if (ret != 0)
{
LOG_DEBUG("event_base_loop returned: %d", (int) ret);
}
if (ret < 0)
break;
event_queue_process(hub->queue);
}
while (hub->status == hub_status_running);
while (hub->status == hub_status_running || hub->status == hub_status_disabled);
}
void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
{
struct event_data post;
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_DESTROY;
post.ptr = user;
event_queue_post(hub->queue, &post);
if (user->id.sid)
{
sid_free(hub->users->sids, user->id.sid);
}
}
void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason)
{
struct event_data post;
int need_notify = 0;
/* is user already being disconnected ? */
if (user_is_disconnecting(user))
{
return;
}
/* stop reading from user */
net_shutdown_r(user->net.connection.sd);
LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state);
need_notify = user_is_logged_in(user);
user->quit_reason = reason;
user_set_state(user, state_cleanup);
if (need_notify)
{
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_QUIT;
post.ptr = user;
event_queue_post(hub->queue, &post);
}
else
{
hub_schedule_destroy_user(hub, user);
}
}
void hub_logout_log(struct hub_info* hub, struct hub_user* user)
{
struct hub_logout_info* loginfo = hub_malloc_zero(sizeof(struct hub_logout_info));
if (!loginfo) return;
loginfo->time = time(NULL);
strcpy(loginfo->cid, user->id.cid);
strcpy(loginfo->nick, user->id.nick);
memcpy(&loginfo->addr, &user->net.ipaddr, sizeof(struct ip_addr_encap));
loginfo->reason = user->quit_reason;
list_append(hub->logout_info, loginfo);
while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log)
{
struct hub_logout_info* entry = list_get_first(hub->logout_info);
list_remove(hub->logout_info, entry);
hub_free(entry);
}
}

View File

@@ -79,22 +79,25 @@ struct hub_stats
size_t net_rx_total;
};
struct hub_logout_info
{
time_t time;
char cid[MAX_CID_LEN+1];
char nick[MAX_NICK_LEN+1];
struct ip_addr_encap addr;
enum user_quit_reason reason;
};
struct hub_info
{
int fd_tcp;
#ifdef ADC_UDP_OPERATION
int fd_udp;
#endif
struct event ev_accept;
struct event ev_timer;
#ifdef ADC_UDP_OPERATION
struct event ev_datagram;
#endif
struct hub_stats stats;
struct event_queue* queue;
struct event_base* evbase;
struct hub_config* config;
struct user_manager* users;
struct hub_user_manager* users;
struct acl_handle* acl;
struct adc_message* command_info; /* The hub's INF command */
struct adc_message* command_support; /* The hub's SUP command */
@@ -102,6 +105,12 @@ struct hub_info
struct adc_message* command_banner; /* The default welcome message */
time_t tm_started;
int status;
char* recvbuf; /* Global receive buffer */
char* sendbuf; /* Global send buffer */
struct linked_list* chat_history; /* Chat history */
struct linked_list* logout_info; /* Log of people logging out. */
#ifdef SSL_SUPPORT
SSL_METHOD* ssl_method;
SSL_CTX* ssl_ctx;
@@ -116,106 +125,104 @@ struct hub_info
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_message(struct user* u, const char* message, size_t length);
extern int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* message, size_t length);
/**
* Handle protocol support/subscription messages received clients.
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_support(struct user* u, struct adc_message* cmd);
extern int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Handle password messages received from clients.
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_password(struct user* u, struct adc_message* cmd);
extern int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Handle chat messages received from clients.
* @return 0 on success, -1 on error.
*/
extern int hub_handle_chat_message(struct user* u, struct adc_message* cmd);
extern int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Add a chat message to the chat history
*/
extern void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd);
/**
* Clear the chat history.
*/
extern void hub_chat_history_clear(struct hub_info* hub);
/**
* Used internally by hub_handle_info
* @return 1 if nickname is OK, or 0 if nickname is not accepted.
*/
extern int hub_handle_info_check_nick(struct user* u, struct adc_message* cmd);
extern int hub_handle_info_check_nick(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Used internally by hub_handle_info
* @return 1 if CID/PID is OK, or 0 if not valid.
*/
extern int hub_handle_info_check_cid(struct user* u, struct adc_message* cmd);
/**
* Can only be used by administrators or operators.
*
* @return 0 on success, -1 on error
*/
extern int hub_handle_kick(struct user* u, struct adc_message* cmd);
#ifdef ADC_UDP_OPERATION
/**
* Handle incoming autocheck message.
*/
extern int hub_handle_autocheck(struct user* u, struct adc_message* cmd);
#endif
extern int hub_handle_info_check_cid(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd);
/**
* Send the support line for the hub to a particular user.
* Only used during the initial handshake.
*/
extern void hub_send_support(struct user* u);
extern void hub_send_support(struct hub_info* hub, struct hub_user* u);
/**
* Send a message assigning a SID for a user.
* This is only sent after hub_send_support() during initial handshake.
*/
extern void hub_send_sid(struct user* u);
extern void hub_send_sid(struct hub_info* hub, struct hub_user* u);
/**
* Send a 'ping' message to user.
*/
extern void hub_send_ping(struct user* user);
extern void hub_send_ping(struct hub_info* hub, struct hub_user* user);
/**
* Send a message containing hub information to a particular user.
* This is sent during user connection, but can safely be sent at any
* point later.
*/
extern void hub_send_hubinfo(struct user* u);
extern void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u);
/**
* Send handshake. This basically calls
* hub_send_support() and hub_send_sid()
*/
extern void hub_send_handshake(struct user* u);
extern void hub_send_handshake(struct hub_info* hub, struct hub_user* u);
/**
* Send a welcome message containing the message of the day to
* one particular user. This can be sent in any point in time.
*/
extern void hub_send_motd(struct user* u);
extern void hub_send_motd(struct hub_info* hub, struct hub_user* u);
/**
* Send a password challenge to a user.
* This is only used if the user tries to access the hub using a
* password protected nick name.
*/
extern void hub_send_password_challenge(struct user* u);
extern void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u);
/**
* Send an autocheck message to a user.
* This is basically a UDP message. The user's client can then determine
* if UDP communication works by either hole punching or configuring UPnP.
* Sends a status_message to a user.
*/
extern void hub_send_autocheck(struct user* u, uint16_t port, const char* token);
extern void hub_send_status(struct hub_info*, struct hub_user* user, enum status_message msg, enum msg_status_level level);
/**
* This starts the hub.
* Allocates memory, initializes the hub based on the configuration,
* and returns a hub handle.
* This hub handle must be passed to hub_shutdown_service() in order to cleanup before exiting.
*
* @return a pointer to the hub info.
*/
extern struct hub_info* hub_start_service(struct hub_config* config);
@@ -238,11 +245,7 @@ extern void hub_free_variables(struct hub_info* hub);
* Returns a string for the given status_message (See enum status_message).
*/
extern const char* hub_get_status_message(struct hub_info* hub, enum status_message msg);
/**
* Sends a status_message to a user.
*/
extern void hub_send_status(struct user* user, enum status_message msg, enum msg_status_level level);
extern const char* hub_get_status_message_log(struct hub_info* hub, enum status_message msg);
/**
* Returns the number of logged in users on the hub.
@@ -340,6 +343,21 @@ extern void hub_schedule_runslice(struct hub_info* hub);
*/
extern void hub_event_loop(struct hub_info* hub);
/**
* Schedule destroying a user.
*/
extern void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user);
/**
* Disconnect a user from the hub.
*/
extern void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason);
/**
* Log a user logging out.
*/
extern void hub_logout_log(struct hub_info* hub, struct hub_user* user);
#endif /* HAVE_UHUB_HUB_H */

96
src/core/hubevent.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
static void log_user_login(struct hub_user* u)
{
const char* cred = get_user_credential_string(u->credentials);
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("LoginOK %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, cred, u->user_agent);
}
static void log_user_login_error(struct hub_user* u, enum status_message msg)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
const char* message = hub_get_status_message_log(u->hub, msg);
LOG_USER("LoginError %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message, u->user_agent);
}
static void log_user_logout(struct hub_user* u, const char* message)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("Logout %s/%s %s \"%s\" (%s)", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message);
}
static void log_user_nick_change(struct hub_user* u, const char* nick)
{
const char* addr = ip_convert_to_string(&u->net.ipaddr);
LOG_USER("NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick);
}
/* Send MOTD, do logging etc */
void on_login_success(struct hub_info* hub, struct hub_user* u)
{
/* Send user list of all existing users */
if (!uman_send_user_list(hub, u))
return;
/* Mark as being in the normal state, and add user to the user list */
user_set_state(u, state_normal);
uman_add(hub, u);
/* Print log message */
log_user_login(u);
/* Announce new user to all connected users */
if (user_is_logged_in(u))
route_info_message(hub, u);
/* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(hub, u);
/* reset to idle timeout */
user_set_timeout(u, TIMEOUT_IDLE);
}
void on_login_failure(struct hub_info* hub, struct hub_user* u, enum status_message msg)
{
log_user_login_error(u, msg);
hub_send_status(hub, u, msg, status_level_fatal);
hub_disconnect_user(hub, u, quit_logon_error);
}
void on_nick_change(struct hub_info* hub, struct hub_user* u, const char* nick)
{
if (user_is_logged_in(u))
{
log_user_nick_change(u, nick);
}
}
void on_logout_user(struct hub_info* hub, struct hub_user* user)
{
const char* reason = user_get_quit_reason_string(user->quit_reason);
log_user_logout(user, reason);
hub_logout_log(hub, user);
}

View File

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

213
src/core/hubio.c Normal file
View File

@@ -0,0 +1,213 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#include "hubio.h"
// #define SEND_CHUNKS 1
/* FIXME: This should not be needed! */
extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ
static void debug_msg(const char* prefix, struct adc_message* msg)
{
size_t n;
char* buf = strdup(msg->cache);
for (n = 0; n < msg->length; n++)
{
if (buf[n] == '\r' || buf[n] == '\n')
buf[n] = '_';
}
LOG_TRACE("%s: [%s] (%d bytes)", prefix, buf, (int) msg->length);
free(buf);
}
#endif
struct hub_recvq* hub_recvq_create()
{
struct hub_recvq* q = hub_malloc_zero(sizeof(struct hub_recvq));
return q;
}
void hub_recvq_destroy(struct hub_recvq* q)
{
if (q)
{
hub_free(q->buf);
hub_free(q);
}
}
size_t hub_recvq_get(struct hub_recvq* q, void* buf, size_t bufsize)
{
assert(bufsize >= q->size);
if (q->size)
{
size_t n = q->size;
memcpy(buf, q->buf, n);
hub_free(q->buf);
q->buf = 0;
q->size = 0;
return n;
}
return 0;
}
size_t hub_recvq_set(struct hub_recvq* q, void* buf, size_t bufsize)
{
if (q->buf)
{
hub_free(q->buf);
q->buf = 0;
q->size = 0;
}
if (!bufsize)
{
return 0;
}
q->buf = hub_malloc(bufsize);
if (!q->buf)
return 0;
q->size = bufsize;
memcpy(q->buf, buf, bufsize);
return bufsize;
}
struct hub_sendq* hub_sendq_create()
{
struct hub_sendq* q = hub_malloc_zero(sizeof(struct hub_sendq));
if (!q)
return 0;
q->queue = list_create();
if (!q->queue)
{
hub_free(q);
return 0;
}
return q;
}
static void clear_send_queue_callback(void* ptr)
{
adc_msg_free((struct adc_message*) ptr);
}
void hub_sendq_destroy(struct hub_sendq* q)
{
if (q)
{
list_clear(q->queue, &clear_send_queue_callback);
list_destroy(q->queue);
hub_free(q);
}
}
void hub_sendq_add(struct hub_sendq* q, struct adc_message* msg_)
{
struct adc_message* msg = adc_msg_incref(msg_);
#ifdef DEBUG_SENDQ
debug_msg("hub_sendq_add", msg);
#endif
list_append(q->queue, msg);
q->size += msg->length;
}
void hub_sendq_remove(struct hub_sendq* q, struct adc_message* msg)
{
#ifdef DEBUG_SENDQ
debug_msg("hub_sendq_remove", msg);
#endif
list_remove(q->queue, msg);
q->size -= msg->length;
adc_msg_free(msg);
q->offset = 0;
}
int hub_sendq_send(struct hub_sendq* q, hub_recvq_write w, void* data)
{
int ret = 0;
size_t bytes = 0;
size_t offset = q->offset; // offset into first message.
size_t remain = 0;
size_t length = 0;
char* sbuf = g_hub->sendbuf;
size_t max_send_buf = 4096;
/* Copy as many messages possible into global send queue */
struct adc_message* msg = list_get_first(q->queue);
while (msg)
{
length = MIN(msg->length - offset, (max_send_buf-1) - bytes);
memcpy(sbuf + bytes, msg->cache + offset, length);
bytes += length;
if (length < (msg->length - offset))
break;
offset = 0;
msg = list_get_next(q->queue);
}
msg = list_get_first(q->queue);
/* Send as much as possible */
ret = w(data, sbuf, bytes);
if (ret > 0)
{
#ifdef SSL_SUPPORT
q->last_write_n = ret;
#endif
/* Remove messages sent */
offset = q->offset;
remain = ret;
while (msg)
{
length = msg->length - offset;
if (length >= remain)
{
q->offset += remain;
break;
}
remain -= length;
hub_sendq_remove(q, msg);
msg = list_get_next(q->queue);
offset = 0;
}
}
return ret;
}
int hub_sendq_is_empty(struct hub_sendq* q)
{
return (q->size - q->offset) == 0;
}
size_t hub_sendq_get_bytes(struct hub_sendq* q)
{
return q->size - q->offset;
}

107
src/core/hubio.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_HUB_IO_H
#define HAVE_UHUB_HUB_IO_H
struct adc_message;
struct linked_list;
typedef int (*hub_recvq_write)(void* desc, const void* buf, size_t len);
typedef int (*hub_recvq_read)(void* desc, void* buf, size_t len);
struct hub_sendq
{
size_t size; /** Size of send queue (in bytes, not messages) */
size_t offset; /** Queue byte offset in the first message. Should be 0 unless a partial write. */
#ifdef SSL_SUPPORT
size_t last_send; /** When using SSL, one have to send the exact same buffer and length if a write cannot complete. */
#endif
struct linked_list* queue; /** List of queued messages */
};
struct hub_recvq
{
char* buf;
size_t size;
};
/**
* Create a send queue
*/
extern struct hub_sendq* hub_sendq_create();
/**
* Destroy a send queue, and delete any queued messages.
*/
extern void hub_sendq_destroy(struct hub_sendq*);
/**
* Add a message to the send queue.
*/
extern void hub_sendq_add(struct hub_sendq*, struct adc_message* msg);
/**
* Process the send queue, and send as many messages as possible.
* @returns the number of bytes sent.
* FIXME: send error not handled here!
*/
extern int hub_sendq_send(struct hub_sendq*, hub_recvq_write, void* data);
/**
* @returns 1 if send queue is empty, 0 otherwise.
*/
extern int hub_sendq_is_empty(struct hub_sendq*);
/**
* @returns the number of bytes remaining to be sent in the queue.
*/
extern size_t hub_sendq_get_bytes(struct hub_sendq*);
/**
* Create a receive queue.
*/
extern struct hub_recvq* hub_recvq_create();
/**
* Destroy a receive queue.
*/
extern void hub_recvq_destroy(struct hub_recvq*);
/**
* Gets the buffer, copies it into buf and deallocates it.
* NOTE: bufsize *MUST* be larger than the buffer, otherwise it asserts.
* @return the number of bytes copied into buf.
*/
extern size_t hub_recvq_get(struct hub_recvq*, void* buf, size_t bufsize);
/**
* Sets the buffer
*/
extern size_t hub_recvq_set(struct hub_recvq*, void* buf, size_t bufsize);
/**
* @return 1 if size is zero, 0 otherwise.
*/
extern int hub_recvq_is_empty(struct hub_recvq* buf);
#endif /* HAVE_UHUB_HUB_IO_H */

View File

@@ -39,9 +39,7 @@ static void remove_server_restricted_flags(struct adc_message* cmd)
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_REFERER);
}
static int user_is_protected(struct user* user);
static int set_feature_cast_supports(struct user* u, struct adc_message* cmd)
static int set_feature_cast_supports(struct hub_user* u, struct adc_message* cmd)
{
char *it, *tmp;
@@ -89,7 +87,7 @@ static int check_hash_tiger(const char* cid, const char* pid)
/*
* FIXME: Only works for tiger hash. If a client doesnt support tiger we cannot let it in!
*/
static int check_cid(struct user* user, struct adc_message* cmd)
static int check_cid(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
size_t pos;
char* cid = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);
@@ -150,7 +148,7 @@ static int check_cid(struct user* user, struct adc_message* cmd)
}
static int check_required_login_flags(struct user* user, struct adc_message* cmd)
static int check_required_login_flags(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
int num = 0;
@@ -186,12 +184,12 @@ static int check_required_login_flags(struct user* user, struct adc_message* cmd
* remove any wrong address, and replace it with the correct one
* as seen by the hub.
*/
int check_network(struct user* user, struct adc_message* cmd)
int check_network(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
const char* address = ip_convert_to_string(&user->ipaddr);
const char* address = ip_convert_to_string(&user->net.ipaddr);
/* Check for NAT override address */
if (acl_is_ip_nat_override(user->hub->acl, address))
if (acl_is_ip_nat_override(hub->acl, address))
{
char* client_given_ip = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
if (strcmp(client_given_ip, "0.0.0.0") != 0)
@@ -222,6 +220,13 @@ int check_network(struct user* user, struct adc_message* cmd)
return 0;
}
void strip_network(struct hub_user* user, struct adc_message* cmd)
{
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_ADDR);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV6_UDP_PORT);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_UDP_PORT);
}
static int nick_length_ok(const char* nick)
{
@@ -269,7 +274,7 @@ static int nick_is_utf8(const char* nick)
}
static int check_nick(struct user* user, struct adc_message* cmd)
static int check_nick(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
char* nick;
char* tmp;
@@ -317,10 +322,10 @@ static int check_nick(struct user* user, struct adc_message* cmd)
}
static int check_logged_in(struct user* user, struct adc_message* cmd)
static int check_logged_in(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
struct user* lookup1 = get_user_by_nick(user->hub, user->id.nick);
struct user* lookup2 = get_user_by_cid(user->hub, user->id.cid);
struct hub_user* lookup1 = uman_get_user_by_nick(hub, user->id.nick);
struct hub_user* lookup2 = uman_get_user_by_cid(hub, user->id.cid);
if (lookup1 == user)
{
@@ -331,20 +336,20 @@ static int check_logged_in(struct user* user, struct adc_message* cmd)
{
if (lookup1 == lookup2)
{
hub_log(log_debug, "check_logged_in: exact same user is logged in: %s", user->id.nick);
user_disconnect(lookup1, quit_ghost_timeout);
LOG_DEBUG("check_logged_in: exact same user is logged in: %s", user->id.nick);
hub_disconnect_user(hub, lookup1, quit_ghost_timeout);
return 0;
}
else
{
if (lookup1)
{
hub_log(log_debug, "check_logged_in: nickname is in use: %s", user->id.nick);
LOG_DEBUG("check_logged_in: nickname is in use: %s", user->id.nick);
return status_msg_inf_error_nick_taken;
}
else
{
hub_log(log_debug, "check_logged_in: CID is in use: %s", user->id.cid);
LOG_DEBUG("check_logged_in: CID is in use: %s", user->id.cid);
return status_msg_inf_error_cid_taken;
}
}
@@ -358,7 +363,7 @@ static int check_logged_in(struct user* user, struct adc_message* cmd)
* But this is not something we want to do, and is deprecated in the ADC specification.
* One should rather look at capabilities/features.
*/
static int check_user_agent(struct user* user, struct adc_message* cmd)
static int check_user_agent(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
char* ua_encoded = 0;
char* ua = 0;
@@ -379,19 +384,19 @@ static int check_user_agent(struct user* user, struct adc_message* cmd)
}
static int check_acl(struct user* user, struct adc_message* cmd)
static int check_acl(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
if (acl_is_cid_banned(user->hub->acl, user->id.cid))
if (acl_is_cid_banned(hub->acl, user->id.cid))
{
return status_msg_ban_permanently;
}
if (acl_is_user_banned(user->hub->acl, user->id.nick))
if (acl_is_user_banned(hub->acl, user->id.nick))
{
return status_msg_ban_permanently;
}
if (acl_is_user_denied(user->hub->acl, user->id.nick))
if (acl_is_user_denied(hub->acl, user->id.nick))
{
return status_msg_inf_error_nick_restricted;
}
@@ -399,7 +404,7 @@ static int check_acl(struct user* user, struct adc_message* cmd)
return 0;
}
static int check_limits(struct user* user, struct adc_message* cmd)
static int check_limits(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
char* arg = adc_msg_get_named_argument(cmd, ADC_INF_FLAG_SHARED_SIZE);
if (arg)
@@ -410,8 +415,8 @@ static int check_limits(struct user* user, struct adc_message* cmd)
if (user_is_logged_in(user))
{
user->hub->users->shared_size -= user->limits.shared_size;
user->hub->users->shared_size += shared_size;
hub->users->shared_size -= user->limits.shared_size;
hub->users->shared_size += shared_size;
}
user->limits.shared_size = shared_size;
hub_free(arg);
@@ -427,8 +432,8 @@ static int check_limits(struct user* user, struct adc_message* cmd)
if (user_is_logged_in(user))
{
user->hub->users->shared_files -= user->limits.shared_files;
user->hub->users->shared_files += shared_files;
hub->users->shared_files -= user->limits.shared_files;
hub->users->shared_files += shared_files;
}
user->limits.shared_files = shared_files;
hub_free(arg);
@@ -480,37 +485,37 @@ static int check_limits(struct user* user, struct adc_message* cmd)
if (!user_is_protected(user))
{
if (user->limits.shared_size < hub_get_min_share(user->hub) && hub_get_min_share(user->hub))
if (user->limits.shared_size < hub_get_min_share(hub) && hub_get_min_share(hub))
{
return status_msg_user_share_size_low;
}
if (user->limits.shared_size > hub_get_max_share(user->hub) && hub_get_max_share(user->hub))
if (user->limits.shared_size > hub_get_max_share(hub) && hub_get_max_share(hub))
{
return status_msg_user_share_size_high;
}
if ((user->limits.hub_count_user > hub_get_max_hubs_user(user->hub) && hub_get_max_hubs_user(user->hub)) ||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(user->hub) && hub_get_max_hubs_reg(user->hub)) ||
(user->limits.hub_count_operator > hub_get_max_hubs_op(user->hub) && hub_get_max_hubs_op(user->hub)) ||
(user->limits.hub_count_total > hub_get_max_hubs_total(user->hub) && hub_get_max_hubs_total(user->hub)))
if ((user->limits.hub_count_user > hub_get_max_hubs_user(hub) && hub_get_max_hubs_user(hub)) ||
(user->limits.hub_count_registered > hub_get_max_hubs_reg(hub) && hub_get_max_hubs_reg(hub)) ||
(user->limits.hub_count_operator > hub_get_max_hubs_op(hub) && hub_get_max_hubs_op(hub)) ||
(user->limits.hub_count_total > hub_get_max_hubs_total(hub) && hub_get_max_hubs_total(hub)))
{
return status_msg_user_hub_limit_high;
}
if ((user->limits.hub_count_user < hub_get_min_hubs_user(user->hub) && hub_get_min_hubs_user(user->hub)) ||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(user->hub) && hub_get_min_hubs_reg(user->hub)) ||
(user->limits.hub_count_operator < hub_get_min_hubs_op(user->hub) && hub_get_min_hubs_op(user->hub)))
if ((user->limits.hub_count_user < hub_get_min_hubs_user(hub) && hub_get_min_hubs_user(hub)) ||
(user->limits.hub_count_registered < hub_get_min_hubs_reg(hub) && hub_get_min_hubs_reg(hub)) ||
(user->limits.hub_count_operator < hub_get_min_hubs_op(hub) && hub_get_min_hubs_op(hub)))
{
return status_msg_user_hub_limit_low;
}
if (user->limits.upload_slots < hub_get_min_slots(user->hub) && hub_get_min_slots(user->hub))
if (user->limits.upload_slots < hub_get_min_slots(hub) && hub_get_min_slots(hub))
{
return status_msg_user_slots_low;
}
if (user->limits.upload_slots > hub_get_max_slots(user->hub) && hub_get_max_slots(user->hub))
if (user->limits.upload_slots > hub_get_max_slots(hub) && hub_get_max_slots(hub))
{
return status_msg_user_slots_high;
}
@@ -525,10 +530,10 @@ static int check_limits(struct user* user, struct adc_message* cmd)
* If the hub is configured to allow only registered users and the user
* is not recognized this will return 1.
*/
static int set_credentials(struct user* user, struct adc_message* cmd)
static int set_credentials(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
int ret = 0;
struct user_access_info* info = acl_get_access_info(user->hub->acl, user->id.nick);
struct hub_user_access_info* info = acl_get_access_info(hub->acl, user->id.nick);
if (info)
{
@@ -577,85 +582,14 @@ static int set_credentials(struct user* user, struct adc_message* cmd)
}
/**
* Determines if a user is to be let into the hub even if the hub is "full".
*/
static int user_is_protected(struct user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
/**
* Returns 1 if a user is registered.
* Only registered users will be let in if the hub is configured for registered
* users only.
*/
static int user_is_registered(struct user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_user:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
void update_user_info(struct user* u, struct adc_message* cmd)
{
char prefix[2];
char* argument;
size_t n = 0;
struct adc_message* cmd_new = adc_msg_copy(u->info);
if (!cmd_new)
{
/* FIXME: OOM! */
return;
}
argument = adc_msg_get_argument(cmd, n++);
while (argument)
{
if (strlen(argument) >= 2)
{
prefix[0] = argument[0];
prefix[1] = argument[1];
adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
}
hub_free(argument);
argument = adc_msg_get_argument(cmd, n++);
}
user_set_info(u, cmd_new);
adc_msg_free(cmd_new);
}
static int check_is_hub_full(struct user* user)
static int check_is_hub_full(struct hub_info* hub, struct hub_user* user)
{
/*
* If hub is full, don't let users in, but we still want to allow
* operators and admins to enter the hub.
*/
if (user->hub->config->max_users && user->hub->users->count >= user->hub->config->max_users && !user_is_protected(user))
if (hub->config->max_users && hub->users->count >= hub->config->max_users && !user_is_protected(user))
{
return 1;
}
@@ -663,23 +597,16 @@ static int check_is_hub_full(struct user* user)
}
static int check_registered_users_only(struct user* user)
static int check_registered_users_only(struct hub_info* hub, struct hub_user* user)
{
if (user->hub->config->registered_users_only && !user_is_registered(user))
if (hub->config->registered_users_only && !user_is_registered(user))
{
return 1;
}
return 0;
}
#define INF_CHECK(FUNC, USER, CMD) \
do { \
int ret = FUNC(USER, CMD); \
if (ret < 0) \
return ret; \
} while(0)
static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
static int hub_handle_info_common(struct hub_user* user, struct adc_message* cmd)
{
/* Remove server restricted flags */
remove_server_restricted_flags(cmd);
@@ -690,9 +617,9 @@ static int hub_handle_info_common(struct user* user, struct adc_message* cmd)
return 0;
}
static int hub_handle_info_low_bandwidth(struct user* user, struct adc_message* cmd)
static int hub_handle_info_low_bandwidth(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
if (user->hub->config->low_bandwidth_mode)
if (hub->config->low_bandwidth_mode)
{
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_USER_AGENT);
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_SHARED_FILES);
@@ -711,45 +638,64 @@ static int hub_handle_info_low_bandwidth(struct user* user, struct adc_message*
return 0;
}
int hub_handle_info_login(struct user* user, struct adc_message* cmd)
#define INF_CHECK(FUNC, HUB, USER, CMD) \
do { \
int ret = FUNC(HUB, USER, CMD); \
if (ret < 0) \
return ret; \
} while(0)
int hub_perform_login_checks(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
int need_auth = 0;
/* Make syntax checks. */
INF_CHECK(check_required_login_flags, user, cmd);
INF_CHECK(check_cid, user, cmd);
INF_CHECK(check_nick, user, cmd);
INF_CHECK(check_network, user, cmd);
INF_CHECK(check_user_agent, user, cmd);
INF_CHECK(check_acl, user, cmd);
INF_CHECK(check_logged_in, user, cmd);
INF_CHECK(check_required_login_flags, hub, user, cmd);
INF_CHECK(check_cid, hub, user, cmd);
INF_CHECK(check_nick, hub, user, cmd);
INF_CHECK(check_network, hub, user, cmd);
INF_CHECK(check_user_agent, hub, user, cmd);
INF_CHECK(check_acl, hub, user, cmd);
INF_CHECK(check_logged_in, hub, user, cmd);
return 0;
}
/**
* Perform additional INF checks used at time of login.
*
* @return 0 if success, <0 if error, >0 if authentication needed.
*/
int hub_handle_info_login(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
int code = 0;
INF_CHECK(hub_perform_login_checks, hub, user, cmd);
/* Private ID must never be broadcasted - drop it! */
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
/* FIXME: This needs some cleaning up */
need_auth = set_credentials(user, cmd);
code = set_credentials(hub, user, cmd);
/* Note: this must be done *after* set_credentials. */
if (check_is_hub_full(user))
if (check_is_hub_full(hub, user))
{
return status_msg_hub_full;
}
if (check_registered_users_only(user))
if (check_registered_users_only(hub, user))
{
return status_msg_hub_registered_users_only;
}
INF_CHECK(check_limits, user, cmd);
INF_CHECK(check_limits, hub, user, cmd);
/* strip off stuff if low_bandwidth_mode is enabled */
hub_handle_info_low_bandwidth(user, cmd);
hub_handle_info_low_bandwidth(hub, user, cmd);
/* Set initial user info */
user_set_info(user, cmd);
return need_auth;
return code;
}
/*
@@ -765,7 +711,7 @@ int hub_handle_info_login(struct user* user, struct adc_message* cmd)
* - CID/PID (valid, not taken, etc).
* - IP addresses (IPv4 and IPv6)
*/
int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct adc_message* cmd_unmodified)
{
struct adc_message* cmd = adc_msg_copy(cmd_unmodified);
if (!cmd) return -1; /* OOM */
@@ -789,10 +735,10 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
return 0;
}
int ret = hub_handle_info_login(user, cmd);
int ret = hub_handle_info_login(hub, user, cmd);
if (ret < 0)
{
on_login_failure(user, ret);
on_login_failure(hub, user, ret);
adc_msg_free(cmd);
return -1;
}
@@ -804,7 +750,7 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
post.id = UHUB_EVENT_USER_JOIN;
post.ptr = user;
post.flags = ret; /* 0 - all OK, 1 - need authentication */
event_queue_post(user->hub->queue, &post);
event_queue_post(hub->queue, &post);
adc_msg_free(cmd);
return 0;
}
@@ -821,20 +767,22 @@ int hub_handle_info(struct user* user, const struct adc_message* cmd_unmodified)
*/
if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK))
{
#if ALLOW_CHANGE_NICK
if (!check_nick(user, cmd))
#ifdef ALLOW_CHANGE_NICK
if (!check_nick(hub, user, cmd))
#endif
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK);
}
/* FIXME - What if limits are not met ? */
check_limits(user, cmd);
hub_handle_info_low_bandwidth(user, cmd);
update_user_info(user, cmd);
check_limits(hub, user, cmd);
strip_network(user, cmd);
hub_handle_info_low_bandwidth(hub, user, cmd);
user_update_info(user, cmd);
if (!adc_msg_is_empty(cmd))
{
route_message(user, cmd);
route_message(hub, user, cmd);
}
adc_msg_free(cmd);

View File

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

View File

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

350
src/core/netevent.c Normal file
View File

@@ -0,0 +1,350 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#include "hubio.h"
/* FIXME: This should not be needed! */
extern struct hub_info* g_hub;
#ifdef DEBUG_SENDQ
void debug_sendq_send(struct hub_user* user, int sent, int total)
{
LOG_DUMP("SEND: sd=%d, %d/%d bytes\n", user->net.connection.sd, sent, total);
if (sent == -1)
{
int err = net_error();
LOG_DUMP(" errno: %d - %s\n", err, net_error_string(err));
}
}
void debug_sendq_recv(struct hub_user* user, int received, int max, const char* buffer)
{
LOG_DUMP("RECV: %d/%d bytes\n", received, (int) max);
if (received == -1)
{
int err = net_error();
LOG_DUMP(" errno: %d - %s\n", err, net_error_string(err));
}
else if (received > 0)
{
char* data = hub_malloc_zero(received + 1);
memcpy(data, buffer, received);
LOG_DUMP("RECV: \"%s\"\n", data);
hub_free(data);
}
}
#endif
int net_user_send(void* ptr, const void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = net_send(user->net.connection.sd, buf, len, UHUB_SEND_SIGNAL);
#ifdef DEBUG_SENDQ
debug_sendq_send(user, ret, len);
#endif
if (ret > 0)
{
user_reset_last_write(user);
}
else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR))
{
return -2;
}
else
{
// user->close_flag = quit_socket_error;
return 0;
}
return ret;
}
#ifdef SSL_SUPPORT
int net_user_send_ssl(void* ptr, const void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = SSL_write(user->net.ssl, buf, (int) len);
#ifdef DEBUG_SENDQ
debug_sendq_send(user, ret, len);
#endif
if (ret > 0)
{
user_reset_last_write(user);
}
else if (ret == -1 && net_error() == EWOULDBLOCK)
{
return -2;
}
else
{
// user->close_flag = quit_socket_error;
return 0;
}
return ret;
}
#endif
int net_user_recv(void* ptr, void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = net_recv(user->net.connection.sd, buf, len, 0);
if (ret > 0)
{
user_reset_last_read(user);
}
#ifdef DEBUG_SENDQ
debug_sendq_recv(user, ret, len, buf);
#endif
return ret;
}
#ifdef SSL_SUPPORT
int net_user_recv_ssl(void* ptr, void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = SSL_read(user->net.ssl, buf, len);
if (ret > 0)
{
user_reset_last_read(user);
}
#ifdef DEBUG_SENDQ
debug_sendq_recv(user, ret, len, buf);
#endif
return ret;
}
#endif
int handle_net_read(struct hub_user* user)
{
static char buf[MAX_RECV_BUF];
struct hub_recvq* q = user->net.recv_queue;
size_t buf_size = hub_recvq_get(q, buf, MAX_RECV_BUF);
ssize_t size = net_user_recv(user, &buf[buf_size], MAX_RECV_BUF - buf_size);
if (size > 0)
buf_size += size;
if (size == -1)
{
if (net_error() == EWOULDBLOCK || net_error() == EINTR)
return 0;
return quit_socket_error;
}
else if (size == 0)
{
return quit_disconnected;
}
else
{
char* lastPos = 0;
char* start = buf;
char* pos = 0;
size_t remaining = buf_size;
while ((pos = memchr(start, '\n', remaining)))
{
lastPos = pos;
pos[0] = '\0';
#ifdef DEBUG_SENDQ
LOG_DUMP("PROC: \"%s\" (%d)\n", start, (int) (pos - start));
#endif
if (user_flag_get(user, flag_maxbuf))
{
user_flag_unset(user, flag_maxbuf);
}
else
{
if (((pos - start) > 0) && g_hub->config->max_recv_buffer > (pos - start))
{
if (hub_handle_message(g_hub, user, start, (pos - start)) == -1)
{
return quit_protocol_error;
break;
}
}
}
pos[0] = '\n'; /* FIXME: not needed */
pos ++;
remaining -= (pos - start);
start = pos;
}
if (lastPos)
{
if (remaining < g_hub->config->max_recv_buffer)
{
hub_recvq_set(q, lastPos, remaining);
}
else
{
hub_recvq_set(q, 0, 0);
user_flag_set(user, flag_maxbuf);
}
}
else
{
hub_recvq_set(q, 0, 0);
}
}
return 0;
}
int handle_net_write(struct hub_user* user)
{
while (hub_sendq_get_bytes(user->net.send_queue))
{
int ret = hub_sendq_send(user->net.send_queue, net_user_send, user);
if (ret == -2)
break;
if (ret <= 0)
return quit_socket_error;
}
if (hub_sendq_get_bytes(user->net.send_queue))
{
user_net_io_want_write(user);
}
else
{
user_net_io_want_read(user);
}
return 0;
}
void net_event(int fd, short ev, void *arg)
{
struct hub_user* user = (struct hub_user*) arg;
int flag_close = 0;
#ifdef DEBUG_SENDQ
LOG_TRACE("net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg);
#endif
if (ev & EV_TIMEOUT)
{
if (user_is_connecting(user))
{
flag_close = quit_timeout;
}
else
{
// FIXME: hub is not neccesarily set!
// hub_send_ping(hub, user);
}
}
if (ev & EV_READ)
{
flag_close = handle_net_read(user);
}
else if (ev & EV_WRITE)
{
flag_close = handle_net_write(user);
}
if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
}
static void prepare_user_net(struct hub_info* hub, struct hub_user* user)
{
int fd = user->net.connection.sd;
#ifdef SET_SENDBUG
size_t sendbuf = 0;
size_t recvbuf = 0;
if (net_get_recvbuf_size(fd, &recvbuf) != -1)
{
if (recvbuf > MAX_RECV_BUF || !recvbuf) recvbuf = MAX_RECV_BUF;
net_set_recvbuf_size(fd, recvbuf);
}
if (net_get_sendbuf_size(fd, &sendbuf) != -1)
{
if (sendbuf > MAX_SEND_BUF || !sendbuf) sendbuf = MAX_SEND_BUF;
net_set_sendbuf_size(fd, sendbuf);
}
#endif
net_set_nonblocking(fd, 1);
net_set_nosigpipe(fd, 1);
}
void net_on_accept(int server_fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct hub_user* user = 0;
struct ip_addr_encap ipaddr;
const char* addr;
for (;;)
{
int fd = net_accept(server_fd, &ipaddr);
if (fd == -1)
{
if (net_error() == EWOULDBLOCK)
{
break;
}
else
{
LOG_ERROR("Accept error: %d %s", net_error(), strerror(net_error()));
break;
}
}
addr = ip_convert_to_string(&ipaddr);
/* FIXME: Should have a plugin log this */
LOG_TRACE("Got connection from %s", addr);
/* FIXME: A plugin should perform this check: is IP banned? */
if (acl_is_ip_banned(hub->acl, addr))
{
LOG_INFO("Denied [%s] (IP banned)", addr);
net_close(fd);
continue;
}
user = user_create(hub, fd);
if (!user)
{
LOG_ERROR("Unable to create user after socket accepted. Out of memory?");
net_close(fd);
break;
}
/* Store IP address in user object */
memcpy(&user->net.ipaddr, &ipaddr, sizeof(ipaddr));
prepare_user_net(hub, user);
}
}

View File

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

219
src/core/route.c Normal file
View File

@@ -0,0 +1,219 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
int route_message(struct hub_info* hub, struct hub_user* u, struct adc_message* msg)
{
struct hub_user* target = NULL;
switch (msg->cache[0])
{
case 'B': /* Broadcast to all logged in clients */
route_to_all(hub, msg);
break;
case 'D':
target = uman_get_user_by_sid(hub, msg->target);
if (target)
{
route_to_user(hub, target, msg);
}
break;
case 'E':
target = uman_get_user_by_sid(hub, msg->target);
if (target)
{
route_to_user(hub, target, msg);
route_to_user(hub, u, msg);
}
break;
case 'F':
route_to_subscribers(hub, msg);
break;
default:
/* Ignore the message */
break;
}
return 0;
}
static inline size_t get_max_send_queue(struct hub_info* hub)
{
/* TODO: More dynamic send queue limit, for instance:
* return MAX(hub->config->max_send_buffer, (hub->config->max_recv_buffer * hub_get_user_count(hub)));
*/
return hub->config->max_send_buffer;
}
static inline size_t get_max_send_queue_soft(struct hub_info* hub)
{
return hub->config->max_send_buffer_soft;
}
/*
* @return 1 if send queue is OK.
* -1 if send queue is overflowed
* 0 if soft send queue is overflowed (not implemented at the moment)
*/
static inline int check_send_queue(struct hub_info* hub, struct hub_user* user, struct adc_message* msg)
{
if (user_flag_get(user, flag_user_list))
return 1;
if ((user->net.send_queue->size + msg->length) > get_max_send_queue(hub))
return -1;
if (user->net.send_queue->size > get_max_send_queue_soft(hub) && msg->priority < 0)
return 0;
return 1;
}
int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_message* msg)
{
#ifdef DEBUG_SENDQ
char* data = strndup(msg->cache, msg->length-1);
LOG_PROTO("send %s: \"%s\"", sid_to_string(user->id.sid), data);
free(data);
#endif
if (hub_sendq_is_empty(user->net.send_queue) && !user_flag_get(user, flag_pipeline))
{
/* Perform oportunistic write */
hub_sendq_add(user->net.send_queue, msg);
handle_net_write(user);
}
else
{
if (check_send_queue(hub, user, msg) >= 0)
{
hub_sendq_add(user->net.send_queue, msg);
if (!user_flag_get(user, flag_pipeline))
user_net_io_want_write(user);
}
}
return 1;
}
int route_flush_pipeline(struct hub_info* hub, struct hub_user* u)
{
if (hub_sendq_is_empty(u->net.send_queue))
return 0;
handle_net_write(u);
user_flag_unset(u, flag_pipeline);
return 1;
}
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
route_to_user(hub, user, command);
user = (struct hub_user*) list_get_next(hub->users->list);
}
return 0;
}
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
int do_send;
char* tmp;
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (user->feature_cast)
{
do_send = 1;
tmp = list_get_first(command->feature_cast_include);
while (tmp)
{
if (!user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_include);;
}
if (!do_send) {
user = (struct hub_user*) list_get_next(hub->users->list);
continue;
}
tmp = list_get_first(command->feature_cast_exclude);
while (tmp)
{
if (user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_exclude);
}
if (do_send)
{
route_to_user(hub, user, command);
}
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
return 0;
}
int route_info_message(struct hub_info* hub, struct hub_user* u)
{
if (!user_is_nat_override(u))
{
return route_to_all(hub, u->info);
}
else
{
struct adc_message* cmd = adc_msg_copy(u->info);
const char* address = ip_convert_to_string(&u->net.ipaddr);
struct hub_user* user = 0;
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
user = (struct hub_user*) list_get_first(hub->users->list);
while (user)
{
if (user_is_nat_override(user))
route_to_user(hub, user, cmd);
else
route_to_user(hub, user, u->info);
user = (struct hub_user*) list_get_next(hub->users->list);
}
adc_msg_free(cmd);
}
return 0;
}

View File

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

375
src/core/user.c Normal file
View File

@@ -0,0 +1,375 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef DEBUG_SENDQ
static const char* user_log_str(struct hub_user* user)
{
static char buf[128];
if (user)
{
snprintf(buf, 128, "user={ %p, \"%s\", %s/%s}", user, user->id.nick, sid_to_string(user->id.sid), user->id.cid);
}
else
{
snprintf(buf, 128, "user={ %p }", user);
}
return buf;
}
#endif
struct hub_user* user_create(struct hub_info* hub, int sd)
{
struct hub_user* user = NULL;
LOG_TRACE("user_create(), hub=%p, sd=%d", hub, sd);
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL)
return NULL; /* OOM */
user->net.tm_connected = time(NULL);
user->net.send_queue = hub_sendq_create();
user->net.recv_queue = hub_recvq_create();
net_con_initialize(&user->net.connection, sd, user, EV_READ);
evtimer_set(&user->net.timeout, net_event, user);
event_base_set(hub->evbase, &user->net.timeout);
user_set_timeout(user, TIMEOUT_CONNECTED);
user_set_state(user, state_protocol);
return user;
}
void user_destroy(struct hub_user* user)
{
LOG_TRACE("user_destroy(), user=%p", user);
net_con_close(&user->net.connection);
evtimer_del(&user->net.timeout);
hub_recvq_destroy(user->net.recv_queue);
hub_sendq_destroy(user->net.send_queue);
adc_msg_free(user->info);
user_clear_feature_cast_support(user);
hub_free(user);
}
void user_set_state(struct hub_user* user, enum user_state state)
{
if ((user->state == state_cleanup && state != state_disconnected) || (user->state == state_disconnected))
{
return;
}
user->state = state;
}
void user_set_info(struct hub_user* user, struct adc_message* cmd)
{
adc_msg_free(user->info);
user->info = adc_msg_incref(cmd);
}
void user_update_info(struct hub_user* u, struct adc_message* cmd)
{
char prefix[2];
char* argument;
size_t n = 0;
struct adc_message* cmd_new = adc_msg_copy(u->info);
if (!cmd_new)
{
/* FIXME: OOM! */
return;
}
/*
* FIXME: Optimization potential:
*
* remove parts of cmd that do not really change anything in cmd_new.
* this can save bandwidth if clients send multiple updates for information
* that does not really change anything.
*/
argument = adc_msg_get_argument(cmd, n++);
while (argument)
{
if (strlen(argument) >= 2)
{
prefix[0] = argument[0];
prefix[1] = argument[1];
adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
}
hub_free(argument);
argument = adc_msg_get_argument(cmd, n++);
}
user_set_info(u, cmd_new);
adc_msg_free(cmd_new);
}
static int convert_support_fourcc(int fourcc)
{
switch (fourcc)
{
case FOURCC('B','A','S','0'): /* Obsolete */
#ifndef OLD_ADC_SUPPORT
return 0;
#endif
case FOURCC('B','A','S','E'):
return feature_base;
case FOURCC('A','U','T','0'):
return feature_auto;
case FOURCC('U','C','M','0'):
case FOURCC('U','C','M','D'):
return feature_ucmd;
case FOURCC('Z','L','I','F'):
return feature_zlif;
case FOURCC('B','B','S','0'):
return feature_bbs;
case FOURCC('T','I','G','R'):
return feature_tiger;
case FOURCC('B','L','O','M'):
case FOURCC('B','L','O','0'):
return feature_bloom;
case FOURCC('P','I','N','G'):
return feature_ping;
case FOURCC('L','I','N','K'):
return feature_link;
default:
LOG_DEBUG("Unknown extension: %x", fourcc);
return 0;
}
}
void user_support_add(struct hub_user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags |= feature_mask;
}
int user_flag_get(struct hub_user* user, enum user_flags flag)
{
return user->flags & flag;
}
void user_flag_set(struct hub_user* user, enum user_flags flag)
{
user->flags |= flag;
}
void user_flag_unset(struct hub_user* user, enum user_flags flag)
{
user->flags &= ~flag;
}
void user_set_nat_override(struct hub_user* user)
{
user_flag_set(user, flag_nat);
}
int user_is_nat_override(struct hub_user* user)
{
return user_flag_get(user, flag_nat);
}
void user_support_remove(struct hub_user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags &= ~feature_mask;
}
int user_have_feature_cast_support(struct hub_user* user, char feature[4])
{
char* tmp = list_get_first(user->feature_cast);
while (tmp)
{
if (strncmp(tmp, feature, 4) == 0)
return 1;
tmp = list_get_next(user->feature_cast);
}
return 0;
}
int user_set_feature_cast_support(struct hub_user* u, char feature[4])
{
if (!u->feature_cast)
{
u->feature_cast = list_create();
}
if (!u->feature_cast)
{
return 0; /* OOM! */
}
list_append(u->feature_cast, hub_strndup(feature, 4));
return 1;
}
void user_clear_feature_cast_support(struct hub_user* u)
{
if (u->feature_cast)
{
list_clear(u->feature_cast, &hub_free);
list_destroy(u->feature_cast);
u->feature_cast = 0;
}
}
int user_is_logged_in(struct hub_user* user)
{
if (user->state == state_normal)
return 1;
return 0;
}
int user_is_connecting(struct hub_user* user)
{
if (user->state == state_protocol || user->state == state_identify || user->state == state_verify)
return 1;
return 0;
}
int user_is_protocol_negotiating(struct hub_user* user)
{
if (user->state == state_protocol)
return 1;
return 0;
}
int user_is_disconnecting(struct hub_user* user)
{
if (user->state == state_cleanup || user->state == state_disconnected)
return 1;
return 0;
}
int user_is_protected(struct hub_user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
/**
* Returns 1 if a user is registered.
* Only registered users will be let in if the hub is configured for registered
* users only.
*/
int user_is_registered(struct hub_user* user)
{
switch (user->credentials)
{
case cred_bot:
case cred_user:
case cred_operator:
case cred_super:
case cred_admin:
case cred_link:
return 1;
default:
break;
}
return 0;
}
void user_net_io_want_write(struct hub_user* user)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_net_io_want_write: %s (pending: %d)", user_log_str(user), event_pending(&user->net.event, EV_READ | EV_WRITE, 0));
#endif
net_con_update(&user->net.connection, EV_READ | EV_WRITE);
}
void user_net_io_want_read(struct hub_user* user)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_net_io_want_read: %s (pending: %d)", user_log_str(user), event_pending(&user->net.event, EV_READ | EV_WRITE, 0));
#endif
net_con_update(&user->net.connection, EV_READ);
}
void user_reset_last_write(struct hub_user* user)
{
user->net.tm_last_write = time(NULL);
}
void user_reset_last_read(struct hub_user* user)
{
user->net.tm_last_read = time(NULL);
}
void user_set_timeout(struct hub_user* user, int seconds)
{
#ifdef DEBUG_SENDQ
LOG_TRACE("user_set_timeout to %d seconds: %s", seconds, user_log_str(user));
#endif
struct timeval timeout = { seconds, 0 };
evtimer_add(&user->net.timeout, &timeout);
}
const char* user_get_quit_reason_string(enum user_quit_reason reason)
{
switch (reason)
{
case quit_unknown: return "unknown"; break;
case quit_disconnected: return "disconnected"; break;
case quit_kicked: return "kicked"; break;
case quit_banned: return "banned"; break;
case quit_timeout: return "timeout"; break;
case quit_send_queue: return "send queue"; break;
case quit_memory_error: return "out of memory"; break;
case quit_socket_error: return "socket error"; break;
case quit_protocol_error: return "protocol error"; break;
case quit_logon_error: return "login error"; break;
case quit_hub_disabled: return "hub disabled"; break;
case quit_ghost_timeout: return "ghost"; break;
}
return "unknown";
}

View File

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

283
src/core/usermanager.c Normal file
View File

@@ -0,0 +1,283 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#define USERMANAGER_TIMER
/*
* This callback function is used to clear user objects from the userlist.
* Should only be used in uman_shutdown().
*/
static void clear_user_list_callback(void* ptr)
{
if (ptr)
{
struct hub_user* u = (struct hub_user*) ptr;
/* Mark the user as already being disconnected.
* This prevents the hub from trying to send
* quit messages to other users.
*/
u->credentials = cred_none;
user_destroy(u);
}
}
void uman_update_stats(struct hub_info* hub)
{
const int factor = TIMEOUT_STATS;
struct net_statistics* total;
struct net_statistics* intermediate;
net_stats_get(&intermediate, &total);
hub->stats.net_tx = (intermediate->tx / factor);
hub->stats.net_rx = (intermediate->rx / factor);
hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
hub->stats.net_tx_total = total->tx;
hub->stats.net_rx_total = total->rx;
net_stats_reset();
}
void uman_print_stats(struct hub_info* hub)
{
LOG_INFO("Statistics users=%zu (peak_users=%zu), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
hub->users->count,
hub->users->count_peak,
(int) hub->stats.net_tx / 1024,
(int) hub->stats.net_rx / 1024,
(int) hub->stats.net_tx_peak / 1024,
(int) hub->stats.net_rx_peak / 1024);
}
#ifdef USERMANAGER_TIMER
static void timer_statistics(int fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct timeval timeout = { TIMEOUT_STATS, 0 };
uman_update_stats(hub);
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
}
#endif
int uman_init(struct hub_info* hub)
{
struct hub_user_manager* users = NULL;
#ifdef USERMANAGER_TIMER
struct timeval timeout = { TIMEOUT_STATS, 0 };
#endif
if (!hub)
return -1;
users = (struct hub_user_manager*) hub_malloc_zero(sizeof(struct hub_user_manager));
if (!users)
return -1;
users->list = list_create();
users->sids = sid_pool_create(net_get_max_sockets());
if (!users->list)
{
list_destroy(users->list);
return -1;
}
hub->users = users;
#ifdef USERMANAGER_TIMER
if (hub->evbase)
{
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
}
#endif // 0
return 0;
}
int uman_shutdown(struct hub_info* hub)
{
if (!hub || !hub->users)
return -1;
#ifdef USERMANAGER_TIMER
if (evtimer_pending(&hub->ev_timer, 0))
event_del(&hub->ev_timer);
#endif
if (hub->users->list)
{
list_clear(hub->users->list, &clear_user_list_callback);
list_destroy(hub->users->list);
}
sid_pool_destroy(hub->users->sids);
hub_free(hub->users);
hub->users = 0;
return 0;
}
int uman_add(struct hub_info* hub, struct hub_user* user)
{
if (!hub || !user)
return -1;
if (user->hub)
return -1;
list_append(hub->users->list, user);
hub->users->count++;
hub->users->count_peak = MAX(hub->users->count, hub->users->count_peak);
hub->users->shared_size += user->limits.shared_size;
hub->users->shared_files += user->limits.shared_files;
user->hub = hub;
return 0;
}
int uman_remove(struct hub_info* hub, struct hub_user* user)
{
if (!hub || !user)
return -1;
list_remove(hub->users->list, user);
if (hub->users->count > 0)
{
hub->users->count--;
}
else
{
assert(!"negative count!");
}
hub->users->shared_size -= user->limits.shared_size;
hub->users->shared_files -= user->limits.shared_files;
user->hub = 0;
return 0;
}
struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid)
{
return sid_lookup(hub->users->sids, sid);
}
struct hub_user* uman_get_user_by_cid(struct hub_info* hub, const char* cid)
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.cid, cid) == 0)
return user;
user = (struct hub_user*) list_get_next(hub->users->list);
}
return NULL;
}
struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick)
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.nick, nick) == 0)
return user;
user = (struct hub_user*) list_get_next(hub->users->list);
}
return NULL;
}
size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range)
{
size_t num = 0;
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (ip_in_range(&user->net.ipaddr, range))
{
list_append(users, user);
num++;
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
return num;
}
int uman_send_user_list(struct hub_info* hub, struct hub_user* target)
{
int ret = 1;
user_flag_set(target, flag_user_list);
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on INF or PAS msg */
while (user)
{
if (user_is_logged_in(user))
{
ret = route_to_user(hub, target, user->info);
if (!ret)
break;
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
#if 0
FIXME: FIXME FIXME handle send queue excess
if (!target->send_queue_size)
{
user_flag_unset(target, flag_user_list);
}
#endif
return ret;
}
void uman_send_quit_message(struct hub_info* hub, struct hub_user* leaving)
{
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));
if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
{
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
}
route_to_all(hub, command);
adc_msg_free(command);
}
sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user)
{
sid_t sid = sid_alloc(hub->users->sids, user);
user->id.sid = sid;
return sid;
}

View File

@@ -20,11 +20,11 @@
#ifndef HAVE_UHUB_USER_MANAGER_H
#define HAVE_UHUB_USER_MANAGER_H
struct user_manager
struct hub_user_manager
{
size_t count; /**<< "Number of all fully connected and logged in users" */
size_t count_peak; /**<< "Peak number of users" */
sid_t free_sid; /**<< "The next available SID." */
struct sid_pool* sids;
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct linked_list* list; /**<< "Contains all users" */
@@ -34,55 +34,77 @@ struct user_manager
* Initializes the user manager.
* @return 0 on success, or -1 if error (out of memory).
*/
extern int user_manager_init(struct hub_info* hub);
extern int uman_init(struct hub_info* hub);
/**
* Shuts down the user manager.
* All users will be disconnected and deleted as part of this.
*
* @return 0 on success, or -1 in an error occured (hub is invalid).
*/
extern void user_manager_shutdown(struct hub_info* hub);
extern int uman_shutdown(struct hub_info* hub);
/**
* Generate statistics for logfiles.
*/
extern void user_manager_update_stats(struct hub_info* hub);
extern void user_manager_print_stats(struct hub_info* hub);
extern void uman_update_stats(struct hub_info* hub);
extern void uman_print_stats(struct hub_info* hub);
/**
* Add a new user to the user manager.
* Add a user to the user manager.
*
* @param hub The hub to add the user to
* @param user The user to be added to the hub.
*/
extern void user_manager_add(struct user* user);
extern int uman_add(struct hub_info* hub, struct hub_user* user);
/**
* Remove a user from the user manager.
* This user is connected, and will be moved to the leaving queue, pending
* all messages in the message queue, and resource cleanup.
*
* @return 0 if successfully removed, -1 if error.
*/
extern void user_manager_remove(struct user* user);
extern int uman_remove(struct hub_info* hub, struct hub_user* user);
/**
* Returns a free sid for a new user.
* Returns and allocates an unused session ID (SID).
*/
extern sid_t user_manager_get_free_sid(struct hub_info* hub);
extern sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user);
/**
* Lookup a user based on the session ID (sid).
* NOTE: This will only search connected users.
* Lookup a user based on the session ID (SID).
*
* NOTE: This function will only search connected users, which means
* that SIDs assigned to users who are not yet completely logged in,
* or are in the process of being disconnected will result in this
* function returning NULL even though the sid is not freely available.
*
* FIXME: Is that really safe / sensible ?
* - Makes sense from a message routing point of view.
*
* @return a user if found, or NULL if not found
*/
extern struct user* get_user_by_sid(struct hub_info* hub, sid_t sid);
extern struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid);
/**
* Lookup a user based on the client ID (cid).
* Lookup a user based on the client ID (CID).
* @return a user if found, or NULL if not found
*/
extern struct user* get_user_by_cid(struct hub_info* hub, const char* cid);
extern struct hub_user* uman_get_user_by_cid(struct hub_info* hub, const char* cid);
/**
* Lookup a user based on the nick name.
* @return a user if found, or NULL if not found
*/
extern struct user* get_user_by_nick(struct hub_info* hub, const char* nick);
extern struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick);
/**
* Lookup users based on an ip address range.
*
* @return The number of users matching the addressess, or -1 on error (mask is wrong).
*/
extern size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range);
/**
* Send the user list of connected clients to 'user'.
@@ -90,13 +112,13 @@ extern struct user* get_user_by_nick(struct hub_info* hub, const char* nick);
*
* @return 1 if sending the user list succeeded, 0 otherwise.
*/
extern int send_user_list(struct user* user);
extern int uman_send_user_list(struct hub_info* hub, struct hub_user* user);
/**
* Send a quit message to all connected users when 'user' is
* leaving the hub (for whatever reason).
*/
extern void send_quit_message(struct user* user);
extern void uman_send_quit_message(struct hub_info* hub, struct hub_user* user);
#endif /* HAVE_UHUB_USER_MANAGER_H */

View File

@@ -1,122 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
static void log_user_login(struct user* u)
{
const char* cred = get_user_credential_string(u->credentials);
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "LoginOK %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, cred, u->user_agent);
}
static void log_user_login_error(struct user* u, enum status_message msg)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
const char* message = hub_get_status_message(u->hub, msg);
hub_log(log_user, "LoginError %s/%s %s \"%s\" (%s) \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message, u->user_agent);
}
static void log_user_logout(struct user* u, const char* message)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "Logout %s/%s %s \"%s\" (%s)", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, message);
}
static void log_user_nick_change(struct user* u, const char* nick)
{
const char* addr = ip_convert_to_string(&u->ipaddr);
hub_log(log_user, "NickChange %s/%s %s \"%s\" -> \"%s\"", sid_to_string(u->id.sid), u->id.cid, addr, u->id.nick, nick);
}
/* Send MOTD, do logging etc */
void on_login_success(struct user* u)
{
struct timeval timeout = { TIMEOUT_IDLE, 0 };
/* Send user list of all existing users */
if (!send_user_list(u))
return;
/* Mark as being in the normal state, and add user to the user list */
user_set_state(u, state_normal);
user_manager_add(u);
/* Print log message */
log_user_login(u);
/* Announce new user to all connected users */
if (user_is_logged_in(u))
route_info_message(u);
/* Send message of the day (if any) */
if (user_is_logged_in(u)) /* Previous send() can fail! */
hub_send_motd(u);
/* reset to idle timeout */
if (u->ev_read)
event_add(u->ev_read, &timeout);
}
void on_login_failure(struct user* u, enum status_message msg)
{
log_user_login_error(u, msg);
hub_send_status(u, msg, status_level_fatal);
user_disconnect(u, quit_logon_error);
}
void on_nick_change(struct user* u, const char* nick)
{
if (user_is_logged_in(u))
{
log_user_nick_change(u, nick);
}
}
void on_logout_user(struct user* user)
{
const char* reason = "";
/* These are used for logging purposes */
switch (user->quit_reason)
{
case quit_disconnected: reason = "disconnected"; break;
case quit_kicked: reason = "kicked"; break;
case quit_banned: reason = "banned"; break;
case quit_timeout: reason = "timeout"; break;
case quit_send_queue: reason = "send queue"; break;
case quit_memory_error: reason = "out of memory"; break;
case quit_socket_error: reason = "socket error"; break;
case quit_protocol_error: reason = "protocol error"; break;
case quit_logon_error: reason = "login error"; break;
case quit_hub_disabled: reason = "hub disabled"; break;
case quit_ghost_timeout: reason = "ghost"; break;
default:
if (user->hub->status == hub_status_shutdown)
reason = "hub shutdown";
else
reason = "unknown error";
break;
}
log_user_logout(user, reason);
user->quit_reason = 0;
}

View File

@@ -1,332 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
void net_on_read(int fd, short ev, void *arg)
{
static char buf[MAX_RECV_BUF];
struct user* user = (struct user*) arg;
char* pos;
size_t offset;
size_t buflen;
ssize_t size;
int more = 1;
int flag_close = 0;
hub_log(log_trace, "net_on_read() : fd=%d, ev=%d, arg=%p", fd, (int) ev, arg);
if (ev == EV_TIMEOUT)
{
more = 0;
if (user_is_connecting(user))
{
flag_close = quit_timeout;
}
else
{
hub_send_ping(user);
}
}
while (more)
{
offset = 0;
if (user->recv_buf)
{
memcpy(buf, user->recv_buf, user->recv_buf_offset);
offset = user->recv_buf_offset;
}
size = net_recv(fd, &buf[offset], MAX_RECV_BUF - offset, 0);
if (size == -1)
{
if (net_error() != EWOULDBLOCK)
flag_close = quit_socket_error;
break;
}
else if (size == 0)
{
flag_close = quit_disconnected;
break;
}
else
{
buflen = offset + size;
ssize_t handled = 0;
while ((pos = memchr(&buf[handled], '\n', (buflen - handled))))
{
pos[0] = '\0';
size_t msglen = &pos[0] - &buf[handled];
if (user_flag_get(user, flag_maxbuf))
{
user_flag_unset(user, flag_maxbuf);
}
else
{
if (msglen < user->hub->config->max_recv_buffer)
{
if (hub_handle_message(user, &buf[handled], msglen) == -1)
{
flag_close = quit_protocol_error;
more = 0;
break;
}
}
}
handled += msglen;
handled++;
}
if (handled == 0 && user_flag_get(user, flag_maxbuf))
handled = buflen;
if (!more)
break;
if (handled < buflen)
{
if ((buflen - handled) > user->hub->config->max_recv_buffer)
{
user_flag_set(user, flag_maxbuf);
hub_free(user->recv_buf);
user->recv_buf = 0;
user->recv_buf_offset = 0;
}
else
{
if (!user->recv_buf)
user->recv_buf = hub_malloc(user->hub->config->max_recv_buffer);
if (user->recv_buf)
{
memcpy(user->recv_buf, &buf[handled], buflen - handled);
user->recv_buf_offset = buflen - handled;
}
else
{
flag_close = quit_memory_error;
break;
}
}
}
else
{
if (user->recv_buf)
{
hub_free(user->recv_buf);
user->recv_buf = 0;
user->recv_buf_offset = 0;
}
}
}
}
if (flag_close)
{
user_disconnect(user, flag_close);
return;
}
if (user_is_logged_in(user))
{
if (user->ev_read)
{
struct timeval timeout = { TIMEOUT_IDLE, 0 };
event_add(user->ev_read, &timeout);
}
}
else if (user_is_connecting(user))
{
if (user->ev_read)
{
struct timeval timeout = { TIMEOUT_HANDSHAKE, 0 };
event_add(user->ev_read, &timeout);
}
}
}
void net_on_write(int fd, short ev, void *arg)
{
struct user* user = (struct user*) arg;
struct adc_message* msg;
int ret;
int length;
int close_flag = 0;
msg = list_get_first(user->send_queue);
while (msg)
{
length = msg->length - user->send_queue_offset;
ret = net_send(user->sd, &msg->cache[user->send_queue_offset], length, UHUB_SEND_SIGNAL);
if (ret == 0 || (ret == -1 && net_error() == EWOULDBLOCK))
{
close_flag = 0;
break;
}
else if (ret > 0)
{
user->tm_last_write = time(NULL);
if (ret == length)
{
#ifdef DEBUG_SENDQ
hub_log(log_error, "SENDQ: sent=%d bytes/%d (all), send_queue_size=%d, offset=%d", ret, (int) msg->length, user->send_queue_size, user->send_queue_offset);
#endif
user->send_queue_size -= ret;
user->send_queue_offset = 0;
#ifdef DEBUG_SENDQ
if ((user->send_queue_size < 0) || (user->send_queue_offset < 0))
{
hub_log(log_error, "INVALID: send_queue_size=%d, send_queue_offset=%d", user->send_queue_size, user->send_queue_offset);
}
#endif
list_remove(user->send_queue, msg);
if (user_flag_get(user, flag_user_list) && (msg == user->info || user->send_queue_size == 0))
{
user_flag_unset(user, flag_user_list);
}
adc_msg_free(msg);
msg = 0;
if (user->send_queue_size == 0)
break;
}
else
{
#ifdef DEBUG_SENDQ
hub_log(log_error, "SENDQ: sent=%d bytes/%d (part), send_queue_size=%d, offset=%d", ret, (int) msg->length, user->send_queue_size, user->send_queue_offset);
#endif
user->send_queue_size -= ret;
user->send_queue_offset += ret;
#ifdef DEBUG_SENDQ
if ((user->send_queue_size < 0) || (user->send_queue_offset < 0) || (user->send_queue_offset > msg->length))
{
hub_log(log_error, "INVALID: send_queue_size=%d, send_queue_offset=%d", user->send_queue_size, user->send_queue_offset);
}
#endif
break;
}
}
else
{
close_flag = quit_socket_error;
break;
}
msg = list_get_first(user->send_queue);
}
if (close_flag)
{
user_disconnect(user, close_flag);
}
else
{
if (user->send_queue_size > 0 && user->ev_write)
event_add(user->ev_write, NULL);
}
}
void net_on_accept(int server_fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct user* user = 0;
const char* addr;
struct timeval timeout = { TIMEOUT_CONNECTED, 0 };
for (;;)
{
int fd = net_accept(server_fd);
if (fd == -1)
{
if (net_error() == EWOULDBLOCK)
{
break;
}
else
{
hub_log(log_error, "Accept error: %d %s", net_error(), strerror(net_error()));
break;
}
}
addr = net_get_peer_address(fd);
/* FIXME: Should have a plugin log this */
hub_log(log_trace, "Got connection from %s", addr);
/* FIXME: A plugin should perform this check: is IP banned? */
if (acl_is_ip_banned(hub->acl, addr))
{
hub_log(log_info, "Denied [%s] (IP banned)", addr);
net_close(fd);
continue;
}
user = user_create(hub, fd);
if (!user)
{
hub_log(log_error, "Unable to create user after socket accepted. Out of memory?");
net_close(fd);
break;
}
/* Store IP address in user object */
ip_convert_to_binary(addr, &user->ipaddr);
net_set_nonblocking(fd, 1);
net_set_nosigpipe(fd, 1);
event_set(user->ev_read, fd, EV_READ | EV_PERSIST, net_on_read, user);
event_set(user->ev_write, fd, EV_WRITE, net_on_write, user);
event_base_set(hub->evbase, user->ev_read);
event_base_set(hub->evbase, user->ev_write);
event_add(user->ev_read, &timeout);
}
}
#ifdef ADC_UDP_OPERATION
extern void net_on_packet(int fd, short ev, void *arg)
{
static char buffer[1024] = {0,};
// struct hub_info* hub = (struct hub_info*) arg;
// struct user* user = 0;
ssize_t size;
struct sockaddr_storage from;
socklen_t fromlen;
size = recvfrom(fd, buffer, 1024, 0, (struct sockaddr*) &from, &fromlen);
// FIXME: A plugin should handle this!
hub_log(log_info, "Datagram [%s] (%d bytes)", buffer, (int) size);
}
#endif

View File

@@ -1,326 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef HAVE_EPOLL
// #define DEBUG_EPOLL
static struct epoll_event* events = 0;
static int epfd = -1;
#ifdef DEBUG_EPOLL
static void dump_listeners()
{
int i;
struct net_event_listener* listener;
hub_log(log_dump, "listeners: number=%d", num_connections);
for (i = 0; i < num_connections; i++)
{
listener = &listeners[i];
if (listener)
{
if (listener->fd != -1)
{
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d fd=%d, ptr=%p", i, num_connections, listeners->fd, listeners);
}
else
{
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d (unused)", i, num_connections);
}
listener = 0;
}
}
getc(stdin);
}
#endif
static void set_poll_events(struct epoll_event* handle, short trigger)
{
memset(handle, 0, sizeof(struct epoll_event));
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
handle->events |= EPOLLIN;
if (trigger & evt_write)
handle->events |= EPOLLOUT;
if (trigger & evt_urgent)
handle->events |= EPOLLPRI;
#ifdef EPOLLRDHUP
if (triggers & evt_close)
handle->events |= EPOLLRDHUP;
#endif
}
static short get_poll_events(struct epoll_event* handle)
{
short trig = handle->events;
short evt = 0;
if (trig & EPOLLIN)
evt |= evt_read;
if (trig & EPOLLPRI)
evt |= evt_urgent;
if (trig & EPOLLOUT)
evt |= evt_write;
if (trig & EPOLLHUP)
evt |= evt_close;
if (trig & EPOLLERR)
evt |= evt_error;
#ifdef EPOLLRDHUP
if (trig & EPOLLRDHUP)
evt |= evt_close;
#endif
return evt;
}
int net_initialize(int capacity)
{
int i;
max_connections = capacity;
num_connections = 0;
epfd = epoll_create(max_connections);
if (epfd == -1)
{
hub_log(log_error, "net_initialize(): epoll_create failed");
return -1;
}
events = hub_malloc_zero(sizeof(struct epoll_event) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
return -1;
}
monitor_allocate((size_t) capacity);
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
net_stats_initialize();
return 0;
}
int net_shutdown()
{
hub_log(log_trace, "Shutting down network monitor");
if (epfd != -1)
{
close(epfd);
}
hub_free(events);
hub_free(listeners);
return 0;
}
#ifdef DEBUG_EPOLL
uint64_t get_time_difference_in_msec(struct timeval before, struct timeval after)
{
uint64_t seconds = (after.tv_sec - before.tv_sec);
uint64_t out = seconds*1000;
if (seconds > 0)
out += ((after.tv_usec / 1000) + (1000 - (before.tv_usec / 1000)));
else
out += ((after.tv_usec - before.tv_usec) / 1000);
return out;
}
#endif
int net_wait(int timeout_ms)
{
int fired, n, max, ret;
struct net_event_listener* listener;
#ifdef DEBUG_EPOLL
struct timeval tm_before;
struct timeval tm_after;
gettimeofday(&tm_before, NULL);
dump_listeners();
#endif
fired = epoll_wait(epfd, events, num_connections, timeout_ms);
if (fired == -1) {
if (errno != EINTR)
{
hub_log(log_error, "net_wait(): epoll_wait failed");
}
return -1;
}
for (n = 0; n < fired; n++)
{
listener = (struct net_event_listener*) events[n].data.ptr;
listener->revents = get_poll_events(&events[n]);
hub_log(log_dump, "net_wait(): epoll event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
max = num_connections;
for (n = 0; n < max; n++)
{
listener = &listeners[n];
if (listener && listener->fd != -1 && listener->revents)
{
hub_log(log_dump, "net_wait(): epoll trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
ret = listener->handler(listener);
listener->revents = 0;
}
#ifdef DEBUG_EPOLL
else
{
if (listener)
hub_log(log_dump, "net_wait(): epoll trigger ignore (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
#endif
}
#ifdef DEBUG_EPOLL
gettimeofday(&tm_after, NULL);
size_t diff = (size_t) get_time_difference_in_msec(tm_before, tm_after);
dump_listeners();
hub_log(log_debug, "net_wait(): time=%dms, triggered=%d", diff, fired);
#endif
return 0;
}
int net_add(int fd, short events, void* data, net_event_handler_t handler)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_free_listener();
hub_log(log_trace, "net_add(): adding socket (fd=%d, pos=%d)", fd, pos);
if (!listener)
{
hub_log(log_error, "net_add(): unable to poll more sockets");
return -1;
}
net_event_listener_set(listener, fd, events, data, handler);
set_poll_events(&ev, events);
ev.data.ptr = listener;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
{
hub_log(log_error, "net_add(): epoll_ctl error while adding socket (fd=%d)", fd);
net_event_listener_clear(listener);
return -1;
}
num_connections++;
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
int net_modify(int fd, short events)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_modify(): modifying socket events (fd=%d)", fd);
if (!listener)
{
hub_log(log_error, "net_modify(): unable to find socket.");
return -1;
}
listener->events = events;
set_poll_events(&ev, events);
ev.data.ptr = listener;
if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
hub_log(log_error, "net_add(): epoll_ctl error while modifying socket (fd=%d)", fd);
return -1;
}
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
int net_remove(int fd)
{
struct epoll_event ev;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_remove(): removing socket (fd=%d, pos=%d)", fd, pos);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
return -1;
}
net_event_listener_clear(listener);
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev) < 0)
{
hub_log(log_error, "net_remove(): epoll_ctl error while removing socket (fd=%d)", fd);
return -1;
}
num_connections--;
#ifdef DEBUG_EPOLL
dump_listeners();
#endif
return 0;
}
#endif /* HAVE_EPOLL */

View File

@@ -1,290 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef HAVE_KQUEUE
static struct kevent* events = 0;
static struct kevent* change = 0;
static int kfd = -1;
static void set_poll_events(struct kevent* handle, short trigger)
{
if (!handle) {
hub_log(log_error, "OOOPS!!");
return;
}
memset(handle, 0, sizeof(struct kevent));
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
handle->filter |= EVFILT_READ;
if (trigger & evt_write /* || trigger & evt_accept*/)
handle->filter |= EVFILT_WRITE;
}
static short get_poll_events(struct kevent* handle)
{
short trig = handle->flags;
short evt = 0;
if (trig & EVFILT_READ)
evt |= evt_read;
if (trig & EVFILT_WRITE)
evt |= evt_write;
if (trig & EV_EOF)
{
evt |= evt_close;
if (handle->fflags)
evt |= evt_error;
}
if (handle->filter == -1)
{
evt |= evt_error;
}
if (handle->data)
{
evt |= evt_accept;
}
if (evt)
{
hub_log(log_error, "Evt: fd=%d, filter=%d, flags=%d, fflags=%d, data=%d evt=%#x", handle->ident, handle->filter, handle->flags, handle->fflags, (int) handle->data, evt);
}
return evt;
}
int net_initialize(int capacity)
{
int i;
max_connections = capacity;
num_connections = 0;
kfd = kqueue();
if (kfd == -1)
{
hub_log(log_error, "net_initialize(): kqueue failed");
return -1;
}
events = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
return -1;
}
change = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
if (!events)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
hub_free(events);
return -1;
}
listeners = (void*) hub_malloc_zero(sizeof(struct net_event_listener) * max_connections);
if (!listeners)
{
hub_log(log_error, "net_initialize(): hub_malloc failed");
hub_free(change);
hub_free(events);
return -1;
}
for (i = 0; i < max_connections; i++)
{
listeners[i].fd = -1;
}
net_stats_initialize();
return 0;
}
int net_shutdown()
{
if (kfd != -1) {
return close(kfd);
}
hub_free(events);
hub_free(change);
hub_free(listeners);
return 0;
}
int net_wait(int timeout_ms)
{
int fired, n, max, ret;
struct net_event_listener* listener;
struct timespec timeout = { (timeout_ms / 1000), (timeout_ms % 1000) * 1000 };
fired = kevent(kfd, events, num_connections, change, num_connections, &timeout);
if (fired == -1) {
if (errno != EINTR)
{
hub_log(log_error, "net_wait(): kevent failed");
}
return -1;
}
for (n = 0; n < fired; n++)
{
listener = (struct net_event_listener*) events[n].udata;
if (listener)
{
listener->revents = get_poll_events(&events[n]);
hub_log(log_dump, "net_wait(): kqueue event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
}
}
max = num_connections;
for (n = 0; n < max; n++)
{
listener = &listeners[n];
if (listener && listener->fd != -1 && listener->revents != 0)
{
hub_log(log_dump, "net_wait(): kqueue trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
ret = listener->handler(listener);
listener->revents = 0;
}
}
return 0;
}
int net_add(int fd, short events_, void* data, net_event_handler_t handler)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_add(): adding socket (fd=%d)", fd);
if (listener)
{
/* Already added! */
return -1;
}
listener = monitor_get_free_listener();
if (!listener)
{
hub_log(log_error, "net_add(): unable to poll more sockets");
return -1;
}
net_event_listener_set(listener, fd, events_, data, handler);
event = &events[pos];
set_poll_events(event, events_);
event->ident = fd;
event->flags |= EV_ADD;
event->flags |= EV_ONESHOT;
#ifdef __APPLE__
event->flags |= EV_ENABLE;
#endif
event->udata = listener;
num_connections++;
return 0;
}
int net_modify(int fd, short events_)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_modify(): modifying socket (fd=%d)", fd);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_modify(): unable to find socket (fd=%d)", fd);
return -1;
}
event = &events[pos];
// set_poll_events(event, events_);
event->ident = fd;
event->flags |= EV_ADD;
event->flags |= EV_ONESHOT;
#ifdef __APPLE__
event->flags |= EV_ENABLE;
#endif
return 0;
}
int net_remove(int fd)
{
struct kevent* event;
struct net_event_listener* listener = monitor_get_listener(fd);
hub_log(log_trace, "net_remove(): removing socket (fd=%d)", fd);
if (!listener)
{
/* The socket is not being monitored */
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
return -1;
}
net_event_listener_clear(listener);
event = &events[pos];
event->ident = fd;
event->filter = 0;
event->flags = EV_DELETE;
#ifdef __APPLE__
event->flasg |= EV_DISABLE;
#endif
event->fflags = 0;
event->data = 0;
event->udata = 0;
num_connections--;
return 0;
}
#endif /* HAVE_KQUEUE */

52
src/network/connection.c Normal file
View File

@@ -0,0 +1,52 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
extern struct hub_info* g_hub;
void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events)
{
con->sd = sd;
con->ptr = (void*) ptr;
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr);
event_base_set(g_hub->evbase, &con->event);
event_add(&con->event, 0);
}
void net_con_update(struct net_connection* con, int events)
{
if (event_pending(&con->event, EV_READ | EV_WRITE, 0) == events)
return;
event_del(&con->event);
event_set(&con->event, con->sd, events | EV_PERSIST, net_event, con->ptr);
event_add(&con->event, 0);
}
void net_con_close(struct net_connection* con)
{
if (!event_pending(&con->event, EV_READ | EV_WRITE, 0))
return;
event_del(&con->event);
net_close(con->sd);
con->sd = -1;
}

41
src/network/connection.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_NETWORK_CONNECTION_H
#define HAVE_UHUB_NETWORK_CONNECTION_H
#include "uhub.h"
struct net_connection
{
int sd; /** socket descriptor */
void* ptr; /** data pointer */
struct event event; /** libevent struct for read/write events */
#ifdef SSL_SUPPORT
SSL* ssl; /** SSL handle */
#endif /* SSL_SUPPORT */
};
extern void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events);
extern void net_con_update(struct net_connection* con, int events);
extern void net_con_close(struct net_connection* con);
#endif /* HAVE_UHUB_NETWORK_CONNECTION_H */

View File

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

View File

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

View File

@@ -1,52 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
typedef void (*plugin_event_startup)(struct hub*);
typedef void (*plugin_event_shutdown)(struct hub*);
typedef void (*plugin_event_user_login)(struct hub*, struct user*);
typedef void (*plugin_event_user_logout)(struct hub*, struct user*);
typedef int (*plugin_event_connect)(struct hub*, struct ip_addr_encap);
typedef void (*plugin_event_disconnect)(struct hub*, struct user*);
typedef int (*plugin_event_message)(struct hub*, struct user*, struct adc_message*);
typedef void (*plugin_event_support)(struct hub*, struct user*, int);
struct uhub_plugin
{
/** Starting the hub */
plugin_event_startup evt_startup;
/** Shutting down the hub */
plugin_event_shutdown evt_shutdown;
/** Someone connected to the hub (we only have IP at this point). */
plugin_event_connect evt_connect;
/** Someone disconnected from the hub (but was not successfully logged in). */
plugin_event_disconnect evt_disconnect;
/** A client sent a message about which protocol extensions it supports */
plugin_event_support evt_support;
/** A client was successfully logged in to the hub */
plugin_event_user_login evt_login;
/** A client (previously logged in) has disconnected. */
plugin_event_user_logout evt_logout;
};

View File

@@ -1,266 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
int route_message(struct user* u, struct adc_message* msg)
{
struct user* target = NULL;
switch (msg->cache[0])
{
case 'B': /* Broadcast to all logged in clients */
route_to_all(u->hub, msg);
break;
case 'D':
target = get_user_by_sid(u->hub, msg->target);
if (target)
{
route_to_user(target, msg);
}
break;
case 'E':
target = get_user_by_sid(u->hub, msg->target);
if (target)
{
route_to_user(target, msg);
route_to_user(u, msg);
}
break;
case 'F':
route_to_subscribers(u->hub, msg);
break;
default:
/* Ignore the message */
break;
}
return 0;
}
static void queue_command(struct user* user, struct adc_message* msg__, int offset)
{
struct adc_message* msg = adc_msg_incref(msg__);
list_append(user->send_queue, msg);
#ifdef DEBUG_SENDQ
hub_log(log_trace, "SENDQ: user=%p, msg=%p (%zu), offset=%d, length=%d, total_length=%d", user, msg, msg->references, offset, msg->length, user->send_queue_size);
#endif
user->send_queue_size += msg->length - offset;
if (list_size(user->send_queue) == 1)
{
user->send_queue_offset = offset;
user->tm_last_write = time(NULL);
}
}
// #define ALWAYS_QUEUE_MESSAGES
static size_t get_max_send_queue(struct hub_info* hub)
{
/* TODO: More dynamic send queue limit, for instance:
* return MAX(hub->config->max_send_buffer, (hub->config->max_recv_buffer * hub_get_user_count(hub)));
*/
return hub->config->max_send_buffer;
}
static size_t get_max_send_queue_soft(struct hub_info* hub)
{
return hub->config->max_send_buffer_soft;
}
/*
* @return 1 if send queue is OK.
* -1 if send queue is overflowed
* 0 if soft send queue is overflowed (not implemented at the moment)
*/
static int check_send_queue(struct user* user, struct adc_message* msg)
{
if (user_flag_get(user, flag_user_list))
return 1;
if ((user->send_queue_size + msg->length) > get_max_send_queue(user->hub))
return -1;
if (user->send_queue_size > get_max_send_queue_soft(user->hub) && msg->priority < 0)
return 0;
return 1;
}
int route_to_user(struct user* user, struct adc_message* msg)
{
int ret;
#if LOG_SEND_MESSAGES_WHEN_ROUTED
char* data = strndup(msg->cache, msg->length-1);
hub_log(log_protocol, "send %s: %s", sid_to_string(user->sid), data);
free(data);
#endif
#ifndef ALWAYS_QUEUE_MESSAGES
if (user->send_queue_size == 0 && !user_is_disconnecting(user))
{
ret = net_send(user->sd, msg->cache, msg->length, UHUB_SEND_SIGNAL);
if (ret == msg->length)
{
return 1;
}
if (ret >= 0 || (ret == -1 && net_error() == EWOULDBLOCK))
{
queue_command(user, msg, ret);
if (user->send_queue_size && user->ev_write)
event_add(user->ev_write, NULL);
}
else
{
/* A socket error occured */
user_disconnect(user, quit_socket_error);
return 0;
}
}
else
#endif
{
ret = check_send_queue(user, msg);
if (ret == -1)
{
/* User is not able to swallow the data, let's cut our losses and disconnect. */
user_disconnect(user, quit_send_queue);
}
else if (ret == 1)
{
/* queue command */
queue_command(user, msg, 0);
if (user->ev_write)
event_add(user->ev_write, NULL);
}
else
{
/* do not queue command as our soft-limits are exceeded */
}
}
return 1;
}
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
struct user* user = (struct user*) list_get_first(hub->users->list);
while (user)
{
route_to_user(user, command);
user = (struct user*) list_get_next(hub->users->list);
}
return 0;
}
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
int do_send;
char* tmp;
struct user* user = (struct user*) list_get_first(hub->users->list);
while (user)
{
if (user->feature_cast)
{
do_send = 1;
tmp = list_get_first(command->feature_cast_include);
while (tmp)
{
if (!user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_include);;
}
if (!do_send) {
user = (struct user*) list_get_next(hub->users->list);
continue;
}
tmp = list_get_first(command->feature_cast_exclude);
while (tmp)
{
if (user_have_feature_cast_support(user, tmp))
{
do_send = 0;
break;
}
tmp = list_get_next(command->feature_cast_exclude);
}
if (do_send)
{
route_to_user(user, command);
}
}
user = (struct user*) list_get_next(hub->users->list);
}
return 0;
}
int route_info_message(struct user* u)
{
if (!user_is_nat_override(u))
{
return route_to_all(u->hub, u->info);
}
else
{
struct adc_message* cmd = adc_msg_copy(u->info);
const char* address = ip_convert_to_string(&u->ipaddr);
struct user* user = 0;
adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
user = (struct user*) list_get_first(u->hub->users->list);
while (user)
{
if (user_is_nat_override(user))
route_to_user(user, cmd);
else
route_to_user(user, u->info);
user = (struct user*) list_get_next(u->hub->users->list);
}
adc_msg_free(cmd);
}
return 0;
}

View File

@@ -1,61 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
const char* BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
char* sid_to_string(sid_t sid_)
{
static char t_sid[5];
sid_t sid = (sid_ & 0xFFFFF); /* 20 bits only */
sid_t A, B, C, D = 0;
D = (sid % 32);
sid = (sid - D) / 32;
C = (sid % 32);
sid = (sid - C) / 32;
B = (sid % 32);
sid = (sid - B) / 32;
A = (sid % 32);
t_sid[0] = BASE32_ALPHABET[A];
t_sid[1] = BASE32_ALPHABET[B];
t_sid[2] = BASE32_ALPHABET[C];
t_sid[3] = BASE32_ALPHABET[D];
t_sid[4] = 0;
return t_sid;
}
sid_t string_to_sid(const char* sid)
{
sid_t nsid = 0;
sid_t n, x;
sid_t factors[] = { 32768, 1024, 32, 1};
if (!sid || strlen(sid) != 4) return 0;
for (n = 0; n < 4; n++) {
for (x = 0; x < strlen(BASE32_ALPHABET); x++)
if (sid[n] == BASE32_ALPHABET[x]) break;
if (x == 32) return 0;
nsid += x * factors[n];
}
return nsid;
}

View File

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

View File

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

View File

@@ -1,308 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
struct user* user_create(struct hub_info* hub, int sd)
{
struct user* user = NULL;
hub_log(log_trace, "user_create(), hub=%p, sd=%d", hub, sd);
user = (struct user*) hub_malloc_zero(sizeof(struct user));
if (user == NULL)
return NULL; /* OOM */
user->ev_write = hub_malloc_zero(sizeof(struct event));
user->ev_read = hub_malloc_zero(sizeof(struct event));
if (!user->ev_write || !user->ev_read)
{
hub_free(user->ev_read);
hub_free(user->ev_write);
hub_free(user);
return NULL;
}
user->sd = sd;
user->tm_connected = time(NULL);
user->hub = hub;
user->feature_cast = 0;
user->send_queue = list_create();
user->send_queue_offset = 0;
user->send_queue_size = 0;
user->recv_buf_offset = 0;
user->recv_buf = 0;
user_set_state(user, state_protocol);
return user;
}
static void clear_send_queue_callback(void* ptr)
{
adc_msg_free((struct adc_message*) ptr);
}
void user_destroy(struct user* user)
{
hub_log(log_trace, "user_destroy(), user=%p", user);
if (user->ev_write)
{
event_del(user->ev_write);
hub_free(user->ev_write);
user->ev_write = 0;
}
if (user->ev_read)
{
event_del(user->ev_read);
hub_free(user->ev_read);
user->ev_read = 0;
}
net_close(user->sd);
adc_msg_free(user->info);
user_clear_feature_cast_support(user);
if (user->recv_buf)
{
hub_free(user->recv_buf);
}
if (user->send_queue)
{
list_clear(user->send_queue, &clear_send_queue_callback);
list_destroy(user->send_queue);
}
hub_free(user);
}
void user_set_state(struct user* user, enum user_state state)
{
if ((user->state == state_cleanup && state != state_disconnected) || (user->state == state_disconnected))
{
puts("PANIC - Ignoring new state");
return;
}
user->state = state;
}
void user_set_info(struct user* user, struct adc_message* cmd)
{
adc_msg_free(user->info);
user->info = adc_msg_incref(cmd);
}
static int convert_support_fourcc(int fourcc)
{
switch (fourcc)
{
case FOURCC('B','A','S','0'): /* Obsolete */
case FOURCC('B','A','S','E'):
return feature_base;
case FOURCC('A','U','T','0'):
return feature_auto;
case FOURCC('U','C','M','0'):
case FOURCC('U','C','M','D'):
return feature_ucmd;
case FOURCC('Z','L','I','F'):
return feature_zlif;
case FOURCC('B','B','S','0'):
return feature_bbs;
case FOURCC('T','I','G','R'):
return feature_tiger;
case FOURCC('B','L','O','M'):
case FOURCC('B','L','O','0'):
return feature_bloom;
case FOURCC('P','I','N','G'):
return feature_ping;
case FOURCC('L','I','N','K'):
return feature_link;
default:
hub_log(log_debug, "Unknown extension: %x", fourcc);
return 0;
}
}
void user_support_add(struct user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags |= feature_mask;
}
int user_flag_get(struct user* user, enum user_flags flag)
{
return user->flags & flag;
}
void user_flag_set(struct user* user, enum user_flags flag)
{
user->flags |= flag;
}
void user_flag_unset(struct user* user, enum user_flags flag)
{
user->flags &= ~flag;
}
void user_set_nat_override(struct user* user)
{
user_flag_set(user, flag_nat);
}
int user_is_nat_override(struct user* user)
{
return user_flag_get(user, flag_nat);
}
void user_support_remove(struct user* user, int fourcc)
{
int feature_mask = convert_support_fourcc(fourcc);
user->flags &= ~feature_mask;
}
void user_schedule_destroy(struct user* user)
{
struct event_data post;
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_DESTROY;
post.ptr = user;
event_queue_post(user->hub->queue, &post);
}
void user_disconnect(struct user* user, int reason)
{
struct event_data post;
int need_notify = 0;
if (user_is_disconnecting(user))
{
return;
}
/* dont read more data from this user */
if (user->ev_read)
{
event_del(user->ev_read);
hub_free(user->ev_read);
user->ev_read = 0;
}
hub_log(log_trace, "user_disconnect(), user=%p, reason=%d, state=%d", user, reason, user->state);
need_notify = user_is_logged_in(user);
user->quit_reason = reason;
user_set_state(user, state_cleanup);
if (need_notify)
{
memset(&post, 0, sizeof(post));
post.id = UHUB_EVENT_USER_QUIT;
post.ptr = user;
event_queue_post(user->hub->queue, &post);
}
else
{
user->quit_reason = quit_unknown;
user_schedule_destroy(user);
}
}
int user_have_feature_cast_support(struct user* user, char feature[4])
{
char* tmp = list_get_first(user->feature_cast);
while (tmp)
{
if (strncmp(tmp, feature, 4) == 0)
return 1;
tmp = list_get_next(user->feature_cast);
}
return 0;
}
int user_set_feature_cast_support(struct user* u, char feature[4])
{
if (!u->feature_cast)
{
u->feature_cast = list_create();
}
if (!u->feature_cast)
{
return 0; /* OOM! */
}
list_append(u->feature_cast, hub_strndup(feature, 4));
return 1;
}
void user_clear_feature_cast_support(struct user* u)
{
if (u->feature_cast)
{
list_clear(u->feature_cast, &hub_free);
list_destroy(u->feature_cast);
u->feature_cast = 0;
}
}
int user_is_logged_in(struct user* user)
{
if (user->state == state_normal)
return 1;
return 0;
}
int user_is_connecting(struct user* user)
{
if (user->state == state_protocol || user->state == state_identify || user->state == state_verify)
return 1;
return 0;
}
int user_is_disconnecting(struct user* user)
{
if (user->state == state_cleanup || user->state == state_disconnected)
return 1;
return 0;
}

View File

@@ -1,234 +0,0 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
/*
* This callback function is used to clear user objects from the userlist.
* Should only be used in user_manager_shutdown().
*/
static void clear_user_list_callback(void* ptr)
{
if (ptr)
{
struct user* u = (struct user*) ptr;
/* Mark the user as already being disconnected.
* This prevents the hub from trying to send
* quit messages to other users.
*/
u->credentials = cred_none;
user_destroy(u);
}
}
void user_manager_update_stats(struct hub_info* hub)
{
const int factor = TIMEOUT_STATS;
struct net_statistics* total;
struct net_statistics* intermediate;
net_stats_get(&intermediate, &total);
hub->stats.net_tx = (intermediate->tx / factor);
hub->stats.net_rx = (intermediate->rx / factor);
hub->stats.net_tx_peak = MAX(hub->stats.net_tx, hub->stats.net_tx_peak);
hub->stats.net_rx_peak = MAX(hub->stats.net_rx, hub->stats.net_rx_peak);
hub->stats.net_tx_total = total->tx;
hub->stats.net_rx_total = total->rx;
net_stats_reset();
}
void user_manager_print_stats(struct hub_info* hub)
{
hub_log(log_info, "Statistics users=%zu (peak_users=%zu), net_tx=%d KB/s, net_rx=%d KB/s (peak_tx=%d KB/s, peak_rx=%d KB/s)",
hub->users->count,
hub->users->count_peak,
(int) hub->stats.net_tx / 1024,
(int) hub->stats.net_rx / 1024,
(int) hub->stats.net_tx_peak / 1024,
(int) hub->stats.net_rx_peak / 1024);
}
static void timer_statistics(int fd, short ev, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct timeval timeout = { TIMEOUT_STATS, 0 };
user_manager_update_stats(hub);
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
}
int user_manager_init(struct hub_info* hub)
{
struct user_manager* users = NULL;
struct timeval timeout = { TIMEOUT_STATS, 0 };
users = (struct user_manager*) hub_malloc_zero(sizeof(struct user_manager));
users->list = list_create();
users->free_sid = 1;
if (!users->list)
{
list_destroy(users->list);
return -1;
}
hub->users = users;
evtimer_set(&hub->ev_timer, timer_statistics, hub);
event_base_set(hub->evbase, &hub->ev_timer);
evtimer_add(&hub->ev_timer, &timeout);
return 0;
}
void user_manager_shutdown(struct hub_info* hub)
{
struct user_manager* users = hub->users;
event_del(&hub->ev_timer);
list_clear(users->list, &clear_user_list_callback);
list_destroy(users->list);
hub_free(hub->users);
}
void user_manager_add(struct user* user)
{
list_append(user->hub->users->list, user);
user->hub->users->count++;
user->hub->users->count_peak = MAX(user->hub->users->count, user->hub->users->count_peak);
user->hub->users->shared_size += user->limits.shared_size;
user->hub->users->shared_files += user->limits.shared_files;
}
void user_manager_remove(struct user* user)
{
list_remove(user->hub->users->list, user);
user->hub->users->count--;
user->hub->users->shared_size -= user->limits.shared_size;
user->hub->users->shared_files -= user->limits.shared_files;
}
struct user* get_user_by_sid(struct hub_info* hub, sid_t sid)
{
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users */
while (user)
{
if (user->id.sid == sid)
return user;
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
struct user* get_user_by_cid(struct hub_info* hub, const char* cid)
{
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.cid, cid) == 0)
return user;
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
struct user* get_user_by_nick(struct hub_info* hub, const char* nick)
{
struct user* user = (struct user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
while (user)
{
if (strcmp(user->id.nick, nick) == 0)
return user;
user = (struct user*) list_get_next(hub->users->list);
}
return NULL;
}
int send_user_list(struct user* target)
{
int ret = 1;
user_flag_set(target, flag_user_list);
struct user* user = (struct user*) list_get_first(target->hub->users->list); /* iterate users - only on INF or PAS msg */
while (user)
{
if (user_is_logged_in(user))
{
ret = route_to_user(target, user->info);
if (!ret)
break;
}
user = (struct user*) list_get_next(user->hub->users->list);
}
if (!target->send_queue_size)
{
user_flag_unset(target, flag_user_list);
}
return ret;
}
void send_quit_message(struct user* leaving)
{
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));
if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
{
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
}
route_to_all(leaving->hub, command);
adc_msg_free(command);
}
sid_t user_manager_get_free_sid(struct hub_info* hub)
{
#if 0
struct user* user;
user = (struct user*) list_get_first(hub->users->list); /* iterate normal users */
while (user)
{
if (user->sid == hub->users->free_sid)
{
hub->users->free_sid++;
if (hub->users->free_sid >= SID_MAX) hub->users->free_sid = 1;
break;
}
user = (struct user*) list_get_next(hub->users->list);
}
#endif
return hub->users->free_sid++;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

137
src/util/rbtree.c Normal file
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/>.
*
*/
#if 0
#include <sys/types.h>
#include "rbtree.h"
#define RED 0
#define BLACK 1
struct rb_node
{
const void* key;
const void* value; /* data */
int color;
struct rb_node* parent;
struct rb_node* left;
struct rb_node* right;
};
struct rb_tree
{
struct rb_node* root;
size_t elements;
rb_tree_alloc alloc;
rb_tree_free free;
rb_tree_compare compare;
};
/* returns the grandparent of a node, if it exits */
static inline struct rb_node* get_grandparent(struct rb_node* n)
{
if (n->parent)
return n->parent->parent;
return 0;
}
static struct rb_node* get_uncle(struct rb_node* n)
{
struct rb_node* gparent = n->parent ? n->parent->parent : 0;
if (gparent)
return (n->parent == gparent->left) ? gparent->right : gparent->left;
return 0;
}
static struct rb_node* tree_search(struct rb_tree* tree, const void* key)
{
struct rb_node* node = tree->root;
while (node)
{
int res = tree->compare(key, node->key);
if (res < 0) node = node->left;
else if (res > 0) node = node->right;
else return node;
}
return 0;
}
static struct rb_node* tree_insert(struct rb_tree* tree, const void* key, const void* value)
{
struct rb_node* node = tree->root;
struct rb_node* newnode = tree->alloc(sizeof(struct rb_node));
newnode->key = key;
newnode->value = value;
newnode->color = RED;
while (node)
{
int res = tree->compare(key, node->key);
if (res < 0) node = node->left;
else if (res > 0) node = node->right;
else
{
/* key already exists in tree */
return node;
}
}
return newnode;
}
struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree_free f)
{
struct rb_tree* tree = a(sizeof(struct rb_tree));
tree->compare = compare;
tree->alloc = a;
tree->free = f;
return tree;
}
void rb_tree_destroy(struct rb_tree* tree)
{
rb_tree_free f = tree->free;
f(tree);
}
void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* value)
{
struct rb_node* node = tree_insert(tree, key, value);
if (node)
return (void*) node->value;
return 0;
}
void* rb_tree_remove(struct rb_tree* tree, const void* key)
{
}
void* rb_tree_get(struct rb_tree* tree, const void* key)
{
struct rb_node* node = tree_search(tree, key);
if (node)
return node->value;
return 0;
}
#endif

38
src/util/rbtree.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_RED_BLACK_TREE_H
#define HAVE_UHUB_RED_BLACK_TREE_H
struct rb_tree;
typedef int (*rb_tree_compare)(const void* a, const void* b);
typedef void* (*rb_tree_alloc)(size_t);
typedef void (*rb_tree_free)(void*);
extern struct rb_tree* rb_tree_create(rb_tree_compare, rb_tree_alloc, rb_tree_free);
extern void rb_tree_destroy(struct rb_tree*);
extern void* rb_tree_insert(struct rb_tree* tree, const void* key, const void* data);
extern void* rb_tree_remove(struct rb_tree* tree, const void* key);
extern void* rb_tree_get(struct rb_tree* tree, const void* key);
#endif /* HAVE_UHUB_RED_BLACK_TREE_H */

48
tools/adc-redirector Executable file
View File

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

View File

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