482 Commits

Author SHA1 Message Date
contact
a313a3aead Simplify network.offlineClients
Replace it with a list of all clients (online or offline).

git-svn-id: file:///srv/svn/repo/suika/trunk@482 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-29 14:55:57 +00:00
contact
3f98447c8f contrib/casemap-logs.sh: new utility script
Previous soju versions were storing log without converting the channel
and nick names to their canonical lower-case representation. This could
result in two log directories for the same channel/nick.

This script fixes old log dirs.

git-svn-id: file:///srv/svn/repo/suika/trunk@481 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-26 14:31:54 +00:00
contact
2cba08b50e Introduce deliveredClientMap
Adds more semantics to map[string]string. Simplifies the complicated
mapStringStringCasemapMap type.

git-svn-id: file:///srv/svn/repo/suika/trunk@480 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-26 10:21:14 +00:00
hubert
3cad542811 Fix CHATHISTORY target not being casemapped
git-svn-id: file:///srv/svn/repo/suika/trunk@479 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-26 09:39:52 +00:00
hubert
1b73446cbb Implement casemapping
TL;DR: supports for casemapping, now logs are saved in
casemapped/canonical/tolower form
(eg. in the #channel directory instead of #Channel... or something)

== What is casemapping? ==

see <https://modern.ircdocs.horse/#casemapping-parameter>

== Casemapping and multi-upstream ==

Since each upstream does not necessarily use the same casemapping, and
since casemappings cannot coexist [0],

1. soju must also update the database accordingly to upstreams'
   casemapping, otherwise it will end up inconsistent,
2. soju must "normalize" entity names and expose only one casemapping
   that is a subset of all supported casemappings (here, ascii).

[0] On some upstreams, "emersion[m]" and "emersion{m}" refer to the same
user (upstreams that advertise rfc1459 for example), while on others
(upstreams that advertise ascii) they don't.

Once upstream's casemapping is known (default to rfc1459), entity names
in map keys are made into casemapped form, for upstreamConn,
upstreamChannel and network.

downstreamConn advertises "CASEMAPPING=ascii", and always casemap map
keys with ascii.

Some functions require the caller to casemap their argument (to avoid
needless calls to casemapping functions).

== Message forwarding and casemapping ==

downstream message handling (joins and parts basically):
When relaying entity names from downstreams to upstreams, soju uses the
upstream casemapping, in order to not get in the way of the user.  This
does not brings any issue, as long as soju replies with the ascii
casemapping in mind (solves point 1.).

marshalEntity/marshalUserPrefix:
When relaying entity names from upstreams with non-ascii casemappings,
soju *partially* casemap them: it only change the case of characters
which are not ascii letters.  ASCII case is thus kept intact, while
special symbols like []{} are the same every time soju sends them to
downstreams (solves point 2.).

== Casemapping changes ==

Casemapping changes are not fully supported by this patch and will
result in loss of history.  This is a limitation of the protocol and
should be solved by the RENAME spec.

git-svn-id: file:///srv/svn/repo/suika/trunk@478 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-24 17:15:52 +00:00
delthas
c4cdfba0f2 Increase downstream TCP keepalive interval to 1 hour
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.

git-svn-id: file:///srv/svn/repo/suika/trunk@477 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-24 17:04:44 +00:00
contact
8561350e47 Fix panic on GetCertificate
Fixes the following panic:

    panic: interface conversion: interface {} is tls.Certificate, not *tls.Certificate

git-svn-id: file:///srv/svn/repo/suika/trunk@476 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-19 08:27:19 +00:00
contact
81f1effe62 Reload TLS certs on SIGHUP
References: https://todo.sr.ht/~emersion/soju/42

git-svn-id: file:///srv/svn/repo/suika/trunk@475 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 13:07:03 +00:00
contact
e2bb6fad08 Stop reading X-Forwarded-Port
X-Forwarded-Port contains the destination port, not the source port,
so it isn't useful for our purposes.

Move parsing of X-Forwarded-* header fields to parseForwarded.

git-svn-id: file:///srv/svn/repo/suika/trunk@474 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 12:28:46 +00:00
contact
3e20658a2c Fix Forwarded HTTP header handling
"for" contains the port, if any. "port" doesn't exist.

git-svn-id: file:///srv/svn/repo/suika/trunk@473 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 12:21:38 +00:00
contact
40912ed72d Add support for the Forwarded HTTP header
This is the standard replacing X-Forwarded-*.

git-svn-id: file:///srv/svn/repo/suika/trunk@472 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 11:08:25 +00:00
contact
0fdfbbcb9b Drop "irc" WebSocket subprotocol
The subprotocol hasn't been standardized yet. It looks like the standard
is moving in another direction.

git-svn-id: file:///srv/svn/repo/suika/trunk@471 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 11:02:36 +00:00
contact
2b48b31b18 Don't add "irc" in ALPN list for WebSocket servers
This is incorrect because HTTP listeners don't handle plain IRC
connections. This also prevents net/http from setting up an HTTP/2
server.

git-svn-id: file:///srv/svn/repo/suika/trunk@470 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-18 10:33:30 +00:00
contact
df382ec139 Don't update downstream caps in upstream RPL_WELCOME handler
Prior to being registered, upstreamConn.handleMessage doesn't run
in the user goroutine, it runs in a goroutine specific to the
network. Thus we shouldn't access any user data structure from
there.

downstreamConn.updateSupportedCaps is already called from the
eventUpstreamConnected handler in user.run, the call being removed
was unnecessary.

Closes: https://todo.sr.ht/~emersion/soju/108

git-svn-id: file:///srv/svn/repo/suika/trunk@469 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 17:25:21 +00:00
contact
edca8b005f Don't store history for NickServ
Closes: https://todo.sr.ht/~emersion/soju/104

git-svn-id: file:///srv/svn/repo/suika/trunk@468 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 08:54:29 +00:00
contact
35272526d6 Send NOTICE to downstream when upstream is disconnected
Closes: https://todo.sr.ht/~emersion/soju/76

git-svn-id: file:///srv/svn/repo/suika/trunk@467 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 08:41:07 +00:00
contact
8ad8706f79 Add Unix socket listener
Closes: https://todo.sr.ht/~emersion/soju/51

git-svn-id: file:///srv/svn/repo/suika/trunk@466 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 08:27:40 +00:00
contact
81f4195dd9 Correctly set WebSocket read/write deadline
The methods didn't have pointer receivers. Thus the deadline fields
were only updated for the local variable.

Closes: https://todo.sr.ht/~emersion/soju/106

git-svn-id: file:///srv/svn/repo/suika/trunk@465 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 08:19:12 +00:00
contact
1f128ff7fc Improve ERR_NOSUCHCHANNEL error messages
References: https://todo.sr.ht/~emersion/soju/63

git-svn-id: file:///srv/svn/repo/suika/trunk@464 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-16 08:13:46 +00:00
contact
aba32b60ab Passthrough some ISUPPORT tokens
git-svn-id: file:///srv/svn/repo/suika/trunk@463 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 22:41:37 +00:00
contact
d9616cc92a Properly handle all ISUPPORT negations
git-svn-id: file:///srv/svn/repo/suika/trunk@462 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 22:11:42 +00:00
contact
b8b77b8f0b Use upstream ISUPPORT map for NETWORK
git-svn-id: file:///srv/svn/repo/suika/trunk@461 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 22:08:19 +00:00
contact
f21599af1d Maintain state for upstream ISUPPORT
git-svn-id: file:///srv/svn/repo/suika/trunk@460 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 22:06:36 +00:00
contact
8df7d55f30 Simplify if block in ISUPPORT handler
git-svn-id: file:///srv/svn/repo/suika/trunk@459 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 21:54:32 +00:00
contact
debb110ae8 Extract ISUPPORT CHANMODES/PREFIX to separate functions
git-svn-id: file:///srv/svn/repo/suika/trunk@458 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-15 21:53:46 +00:00
contact
37c710b832 Add Network.{URL,GetUsername,GetRealname}
Just a bunch of helpers that can be re-used.

git-svn-id: file:///srv/svn/repo/suika/trunk@457 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-09 17:55:34 +00:00
hubert
75dee80758 Send correct CHATHISTORY error messages
git-svn-id: file:///srv/svn/repo/suika/trunk@456 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-03-05 08:53:59 +00:00
contact
266a158b44 Add irc to ALPN protocols
The new ALPN token has been approved [1]. We can start using it now.

[1]: https://mailarchive.ietf.org/arch/msg/tls-reg-review/i8YyT82XUtEgR-oXMG3sbyWYT8E/

git-svn-id: file:///srv/svn/repo/suika/trunk@455 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-24 18:41:12 +00:00
hubert
5864fdf0e6 if true return true else return false
Trivial improvement

git-svn-id: file:///srv/svn/repo/suika/trunk@454 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-18 08:40:51 +00:00
contact
4dfac575f6 Use sendTargetBacklog when re-attaching a channel
No need to attempt to send backlog for all targets in the network.
We're only interested in a single channel.

git-svn-id: file:///srv/svn/repo/suika/trunk@453 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-10 12:50:10 +00:00
contact
6ee586ea01 Introduce downstreamConn.sendTargetBacklog
git-svn-id: file:///srv/svn/repo/suika/trunk@452 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-10 12:48:41 +00:00
contact
77f0241cf5 Rename network.history to network.delivered
"History" is over-loaded with e.g. CHATHISTORY support.

git-svn-id: file:///srv/svn/repo/suika/trunk@451 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-10 10:31:34 +00:00
contact
5c1bf5b701 Rename sendNetworkHistory to sendNetworkBacklog
"History" is a little bit over-loaded with CHATHISTORY support.

git-svn-id: file:///srv/svn/repo/suika/trunk@450 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-10 09:23:51 +00:00
contact
5a1f5eadd1 Add support for graceful shutdown
Closes: https://todo.sr.ht/~emersion/soju/45

git-svn-id: file:///srv/svn/repo/suika/trunk@449 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-02-09 16:34:46 +00:00
hubert
f5d025bd79 Request invite-notify to upstreams
... and do not forward INVITEs to downstreams that do not support the
capability.

The downstream capability can be permanent because there is no way for a
client to get the list of people invited to a channel, thus no state can
be corrupted.

git-svn-id: file:///srv/svn/repo/suika/trunk@448 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-31 21:18:51 +00:00
contact
24d2196f8d Forward ISUPPORT NETWORK token
git-svn-id: file:///srv/svn/repo/suika/trunk@447 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-22 11:00:38 +00:00
contact
004e7a4a18 Send RPL_ISUPPORT CHATHISTORY token
git-svn-id: file:///srv/svn/repo/suika/trunk@446 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-22 10:55:06 +00:00
contact
dd8e8e72e7 Update dependencies
In particular, go-irc v3.1.4 should fix empty IRC message handling.

git-svn-id: file:///srv/svn/repo/suika/trunk@445 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-19 18:20:04 +00:00
contact
87407b262d go fmt
git-svn-id: file:///srv/svn/repo/suika/trunk@444 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-10 21:48:58 +00:00
hubert
34cda63f5b Don't forward batch tags
We don't want to have the batch tag when calling uc.produce, otherwise
downstream will end up with junk batch ids.

git-svn-id: file:///srv/svn/repo/suika/trunk@443 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-10 21:48:08 +00:00
contact
e0ef0b2c01 Add in-memory message store
Uses an in-memory ring buffer.

Closes: https://todo.sr.ht/~emersion/soju/96

git-svn-id: file:///srv/svn/repo/suika/trunk@442 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-04 16:18:30 +00:00
contact
c94290b989 Make chat history operations optional in messageStore
Some stores may want not to implement chat history operations.

git-svn-id: file:///srv/svn/repo/suika/trunk@441 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-04 16:17:35 +00:00
contact
c1308993f8 Add store-agnostic message ID format
Allow to query the network ID and entity from the message ID regardless
of the underlying store used.

git-svn-id: file:///srv/svn/repo/suika/trunk@440 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-04 15:26:30 +00:00
contact
ee6517993f Turn messageStore into an interface
This allows for other implementations that aren't based on a filesystem.

git-svn-id: file:///srv/svn/repo/suika/trunk@439 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2021-01-04 13:24:00 +00:00
hubert
b1d4fde2f5 Improve dc.authenticate()'s error messages
git-svn-id: file:///srv/svn/repo/suika/trunk@438 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-12-25 12:37:15 +00:00
hubert
ee16ab9833 Advertise all caps, CAP DEL them on registration
... so that the JOIN/history batch takes into account all capabilities.
Without this commit for example, enabling multi-prefix after the batch
makes the client send NAMES requests for all channels, which generate
needless traffic.

git-svn-id: file:///srv/svn/repo/suika/trunk@437 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-12-25 12:35:20 +00:00
delthas
5843897b92 service: Introduce channel update
This adds the `channel update` service command, which is used to set the
auto-detach, auto-reattach, and message relaying settings of a channel.

Of note is that currently the parser parses `#` as a comment, which
means any `channel update #foo ...` will actually need to be escaped to
`channel update "#foo" ...`

git-svn-id: file:///srv/svn/repo/suika/trunk@436 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-12-14 19:54:02 +00:00
delthas
638a2229cb Add customizable auto-detaching, auto-reattaching, relaying.
This uses the fields added previously to the Channel struct to implement
the actual detaching/reattaching/relaying logic.

The `FilterDefault` values of the messages filters are currently
hardcoded.

The values of the message filters are not currently user-settable.

This introduces a new user event, eventChannelDetach, which stores an
upstreamConn (which might become invalid at the time of processing), and
a channel name, used for auto-detaching. Every time the channel detach
timer is refreshed (by receveing a message, etc.), a new timer is
created on the upstreamChannel, which will dispatch this event after the
duration (and discards the previous timer, if any).

git-svn-id: file:///srv/svn/repo/suika/trunk@435 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-12-14 19:54:02 +00:00
delthas
4ca0db44d3 Introduce Channel.{RelayDetached,ReattachOn,DetachAfter,DetachOn}
This adds several fields to the channel database schema and struct.
These fields will be used to add support for customizable message
relaying through BouncerServ, auto-reattaching, auto-detaching.

- RelayDetached is a filter for which notices to relay through
  BouncerServ for detached channels.
- ReattachOn is a filter for which messages to trigger a channel
  reattach on.
- DetachAfter is the duration after which to automatically detach a
  channel if no matching messages are received.
- DetachOn is a filter for which messages will reset the auto-detach
  timer.

git-svn-id: file:///srv/svn/repo/suika/trunk@434 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-12-14 19:54:02 +00:00
contact
300e4db292 Add .editorconfig
git-svn-id: file:///srv/svn/repo/suika/trunk@433 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2020-11-30 10:39:41 +00:00