56bf73716d
The rationale for increasing the TCP keepalive interval from 15 seconds (default) to 1 hour follows. - Why increasing TCP keepalives for downstream connections is not an issue wrt to detecting connection interruptions The use case of TCP keepalives is detecting whether a TCP connection was forcefully shut down without receiving any TCP FIN or RST frame, when no data are sent from that endpoint to the other peer. If any data is sent from the peer and is not ACKed because the connection was interrupted, the socket will be closed after the TCP RTO (usually a few seconds) anyway, without the need for TCP keepalives. Therefore the only use of TCP keepalives is making sure that a peer that is not writing anything to the socket, and is actively reading and waiting for new stream data to be received, can, - instead of waiting forever to receive packets that will never arrive because the connection was interrupted -, detect this disconnection, close the connection locally, then try to connect again to its peer. This only makes sense from a client point-of-view. When an IRC client is not write(2)ing anything to the socket but is simply waiting for new messages to arrive, ie read(2)ing on the socket, it must ensure that the connection is still alive so that any new messages will indeed be sent to him. So that IRC client should probably enable TCP keepalives. However, when an IRC server is not writing anything to its downstream socket, it doesn't care if it misses any messages from its downstream client: in any case, the downstream client will instantly detect when its messages are not reaching its server, because of the TCP RTO (keepalives are not even needed in the client in that specific case), and will try to reconnect to the server. Thus TCP keepalives should be enabled for upstream connections, in order to make sure that soju does not miss any messages coming from upstream servers, but TCP keepalives are not needed for downstream connections. - Why increasing TCP keepalives for downstream connections is not an issue wrt security, performance, and server socket resources exhaustion TCP keepalives are orthogonal to security. Malicious clients can open thousands of TCP connections and keep them open with minimal bookkeeping, and TCP keepalives will not prevent attacks planning to use up all available sockets to soju. It is also unlikely that soju will keep many connections open, and in the event that thousands of dead, disconnected connections are active in soju, any upstream message that needs to be sent to downstreams will disconnect all disconnected downstreams after the TCP RTO (a few seconds). Performance could only be slightly affected in the few seconds before a TCP RTO if many messages were sent to a very large number of disconnected connections, which is extremely unlikely and not a large impact to performance either. - Why increasing TCP keepalives could be helpful to some clients running on mobile devices In the current state of IRC, most clients running on mobile devices (mostly running Android and iOS) will probably need to stay connected at all times, even when the application is in background, in order to receive private messages and highlight notifications, complete chat history (and possibly reduced connection traffic due to avoiding all the initial messages traffic, including all NAMES and WHO replies which are quite large). This means most IRC clients on mobile devices will keep a socket open at all times, in background. When a mobile device runs on a cellular data connection, it uses the phone wireless radio to transmit all TCP packets, including TCP packets without user data, for example TCP keepalives. On a typical mobile device, a wireless radio consumes significant power when full active, so it switches between several energy states in order to conserve power when not in use. It typically has 3 energy states, from Standby, when no messages are sent, to Low Power, to Full Power; and switches modes on an average time scale of 15s. This means that any time any TCP packet is sent from any socket on the device, the radio switches to a high-power energy state, sends the packet, then stays on that energy state for around 15s, then goes back to Standby. This does include TCP keepalives. If a TCP keepalive of 15s was used, this means that the IRC server would force all clients running on mobile devices to send a TCP keepalive packet at least once every 15s, which means that the radio would stay in its high-power energy state at all times. This would consume a very significant amount of power and use up battery much faster. Even though it would seem at first that a mobile device would have many different sockets open at any time; actually, a typical Android device typically has at one background socket open, with Firebase Cloud Messaging, for receiving instant push notifications (for example, for the equivalent of IRC highlights on other messaging platforms), and perhaps a socket open for the current foreground app. When the current foreground app does not use the network, or when no app is currently used and the phone is in sleep mode, and no notifications are sent, then the device can effectively have no wireless radio usage at all. This makes removing TCP keepalives extremely significant with regard to the mobile device battery usage. Increasing the TCP keepalive from soju lets downstream clients choose their own keepalive interval and therefore possibly save battery for mobile devices. Most modern mobile devices have complex heuristics for when to sleep the CPU and wireless radio, and have specific rules for TCP keepalives depending on the current internet connection, sleep state, etc. By increasing the downstream TCP keepalive to such a high period, soju lets clients choose their most optimal TCP keepalive period, which means that in turn clients can possibly let their mobile device platform choose best that keepalive for them, thus letting them save battery in those cases. |
||
---|---|---|
cmd | ||
config | ||
contrib | ||
doc | ||
.build.yml | ||
.editorconfig | ||
.gitignore | ||
bridge.go | ||
conn.go | ||
db.go | ||
downstream.go | ||
go.mod | ||
go.sum | ||
ident.go | ||
irc.go | ||
LICENSE | ||
Makefile | ||
msgstore_fs.go | ||
msgstore_memory.go | ||
msgstore.go | ||
README.md | ||
server.go | ||
service.go | ||
upstream.go | ||
user.go |
soju
A user-friendly IRC bouncer.
- Multi-user
- Support multiple clients for a single user, with proper backlog synchronization
- Support connecting to multiple upstream servers via a single IRC connection to the bouncer
Usage
See the man page at doc/soju.1.scd
for more information.
Server side
To create an admin user and start soju, run these commands:
go run ./cmd/sojuctl create-user <soju username> -admin
go run ./cmd/soju -listen irc+insecure://127.0.0.1:6667
If you're migrating from ZNC, a tool is available to import users, networks and channels from a ZNC config file:
go run ./contrib/znc-import.go <znc config file>
Client side
soju can operate in two different modes: multi upstream and single upstream.
Single upstream mode
In this mode, 1 upstream connection to a irc server = 1 connection to your soju bouncer.
The easiest and fastest way to use this is to specify the address of the server
in your username in your client configuration. For example to connect to
Freenode, your username will be: <soju username>/chat.freenode.net
. Also set
your soju password in the password field of your client configuration.
This will autoconfigure soju by adding a network with the address
chat.freenode.net
and then autoconnect to it. You will now be able to join
any channel like you would normally do.
Multi upstream mode
In this mode, a single connection to your soju bouncer can handle multiple
upstream connections. You will need to manually configure each upstream
connection using the the special BouncerServ
user.
Connect to your soju server by specifying your soju username in the username field in your client and your password in the password field.
You should now be able to send private messages to the BouncerServ
. You can
send it commands to configure soju. Create new networks:
/msg BouncerServ network create -addr chat.freenode.net -name freenode
/msg BouncerServ network create -addr irc.rizon.net -name rizon
You will now be able to join channels on these networks by specifying their name:
/join #soju/freenode
/join #somechannel/rizon
Notes
soju will automatically save and restore the channels you were connected to.
Contributing
Send patches on the mailing list or on GitHub, report bugs on the issue tracker. Discuss in #soju on Freenode.
License
AGPLv3, see LICENSE.
Copyright (C) 2020 The soju Contributors