Commit Graph

403 Commits

Author SHA1 Message Date
Michael Klishin 01092ff31f
(c) year bumps 2024-01-01 22:02:20 -05:00
Michael Klishin 1b642353ca
Update (c) according to [1]
1. https://investors.broadcom.com/news-releases/news-release-details/broadcom-and-vmware-intend-close-transaction-november-22-2023
2023-11-21 23:18:22 -05:00
Péter Gömöri f3410db503 Web-MQTT: don't call FHC when connection terminates early
When the Web-MQTT connection terminates early because of no supported
subprotocol, `terminate/3` called fhc release although no fhc obtain was
called yet. This was the case even when `use_file_handle_cache` was false,
because `#state.should_use_fhc` was not initialized.

Fixing this avoids the below harmless warning

```
[debug] error updating ets counter <0.1224.0> in table #Ref<0.2797411137.1366163457.189876>:
[{ets, update_counter,
  [#Ref<0.2797411137.1366163457.189876>,
   <0.1224.0>, {5, -1}],
   ...
[warning] FHC: failed to update counter 'obtained_socket', client pid: <0.1224.0>
```
2023-10-06 07:22:01 +02:00
Michael Klishin 71a23c3675 Renaming in follow-up to #8790
{prefix}.enable_file_handle_cache => {prefix}.use_file_handle_cache
2023-07-10 13:35:25 +04:00
Michael Klishin 3339e8dea3 Web MQTT: release FHC handle only if FHC is enabled 2023-07-09 09:16:17 +04:00
Michael Klishin 1402183bc2 Introduce a way to disable FHC use in web_mqtt
Via `web_mqtt.enable_file_handle_cache`
2023-07-09 09:16:17 +04:00
Loïc Hoguin 610af302c6
Add support for LOCAL proxy header
This is what the proxy uses for health checks. In those cases
we use the socket's IP/ports for the connection name as we
have nothing else we can use.
2023-06-23 12:12:58 +02:00
David Ansari 23837c5270 DISCONNECT v5 clients with Server Shutting Down
When RabbitMQ enters maintenance mode / is being drained, all client
connections are closed.

This commit sends a DISCONNECT packet to (Web) MQTT 5.0 clients with
Reason Code "Server shutting down" before the connection is closed.
2023-06-21 17:14:08 +01:00
David Ansari fb7af48df6 Support Will Delay Interval
Previously, the Will Message could be kept in memory in the MQTT
connection process state. Upon termination, the Will Message is sent.

The new MQTT 5.0 feature Will Delay Interval requires storing the Will
Message outside of the MQTT connection process state.

The Will Message should not be stored node local because the client
could reconnect to a different node.

Storing the Will Message in Mnesia is not an option because we want to
get rid of Mnesia. Storing the Will Message in a Ra cluster or in Khepri
is only an option if the Will Payload is small as there is currently no
way in Ra to **efficiently** snapshot large binary data (Note that these
Will Messages are not consumed in a FIFO style workload like messages in
quorum queues. A Will Message needs to be stored for as long as the
Session lasts - up to 1 day by default, but could also be much longer if
RabbitMQ is configured with a higher maximum session expiry interval.)
Usually Will Payloads are small: They are just a notification that its
MQTT session ended abnormally. However, we don't know how users leverage
the Will Message feature. The MQTT protocol allows for large Will Payloads.

Therefore, the solution implemented in this commit - which should work
good enough - is storing the Will Message in a queue.
Each MQTT session which has a Session Expiry Interval and Will Delay
Interval of > 0 seconds will create a queue if the current Network
Connection ends where it stores its Will Message. The Will Message has a
message TTL set (corresponds to the Will Delay Interval) and the queue
has a queue TTL set (corresponds to the Session Expiry Interval).
If the client does not reconnect within the Will Delay Interval, the
message is dead lettered to the configured MQTT topic exchange
(amq.topic by default).

The Will Delay Interval can be set by both publishers and subscribers.
Therefore, the Will Message is the 1st session state that RabbitMQ keeps
for publish-only MQTT clients.

One current limitation of this commit is that a Will Message that is
delayed (i.e. Will Delay Interval is set) and retained (i.e. Will Retain
flag set) will not be retained.
One solution to retain delayed Will Messages is that the retainer
process consumes from a queue and the queue binds to the topic exchange
with a topic starting with `$`, for example `$retain/#`.
The AMQP 0.9.1 Will Message that is dead lettered could then be added a
CC header such that it won't not only be published with the Will Topic,
but also with `$retain` topic. For example, if the Will Topic is `a/b`,
it will publish with routing key `a/b` and CC header `$retain/a/b`.

The reason this is not implemented in this commit is that to keep the
currently broken retained message store behaviour, we would require
creating at least one queue per node and publishing only to that local
queue. In future, once we have a replicated retained message store based
on a Stream for example, we could just publish all retained messages to
the `$retain` topic and thefore into the Stream.
So, for now, we list "retained and delayed Will Messages" as a limitation
that they actually won't be retained.
2023-06-21 17:14:08 +01:00
Chunyi Lyu cd53f59089 Simplify code to start listeners in web_mqtt 2023-06-21 17:14:08 +01:00
Chunyi Lyu 9d716d5443 Disconnect client with duplicate id with normal code 2023-06-21 17:14:08 +01:00
Chunyi Lyu d601c6432e Send disconnect packet from server
- when clients connect with a duplicate client id;
disconnect with reason code session taken over 142
- when keep alive has timed out;
disconnect with reason code keep alive timeout 141
2023-06-21 17:14:08 +01:00
David Ansari 2270a30af0 Point emqtt to rabbitmq/emqtt:master
emqtt repos:
emqx/emqtt PR #196 is based on rabbitmq:otp-26-compatibility
emqx/emqtt PR #198 is based on ansd:master
rabbitmq/master contains both of these 2 PRs cherry-picked.

rabbitmq-server repos:
main branch points emqtt to rabbitmq:otp-26-compatibility
mqtt5 branch points emqtt to rabbitmq:master

Therefore, the current mqtt5 branch is OTP 26 compatible and can support
multiple subscription identifiers.
2023-06-21 17:14:08 +01:00
David Ansari 6e9aa952ea Remove code duplication 2023-06-21 17:14:08 +01:00
Chunyi Lyu c39079f657 Disconnect at pub qos > server max qos
- "If the Server included a Maximum QoS in its CONNACK response
to a Client and it receives a PUBLISH packet with a QoS greater than this
then it uses DISCONNECT with Reason Code 0x9B (QoS not supported)"
- only affects mqtt v5, server max qos is 1
2023-06-21 17:14:08 +01:00
David Ansari f1f8167ec4 Add MQTT v5 feature Maximum Packet Size set by server
"Allow the Client and Server to independently specify the maximum
packet size they support. It is an error for the session partner
to send a larger packet."

This commit implements the part where the Server specifies the maximum
packet size.

"In the case of an error in a CONNECT packet it MAY send a CONNACK
packet containing the Reason Code, before closing the Network
Connection. In the case of an error in any other packet it SHOULD send a
DISCONNECT packet containing the Reason Code before closing the Network
Connection."

This commit implements only the "SHOULD" (second) part, not the "MAY"
(first) part.

There are now 2 different global wide MQTT settings on the server:
1. max_packet_size_unauthenticated which applies to the CONNECT packet
   (and maybe AUTH packet in the future)
2. max_packet_size_authenticated which applies to all other MQTT
   packets (that is, after the client successfully authenticated).

These two settings will apply to all MQTT versions.
In MQTT v5, if a non-CONNECT packet is too large, the server will send a
DISCONNECT packet to the client with Reason Code "Packet Too Large"
before closing the network connection.
2023-06-21 17:14:08 +01:00
David Ansari be6ff92692 Serialise and parse MQTT 5.0 packets 2023-06-21 17:14:08 +01:00
Michael Klishin 55442aa914 Replace @rabbitmq.com addresses with rabbitmq-core@groups.vmware.com
Don't ask why we have to do it. Because reasons!
2023-06-20 15:40:13 +04:00
Rin Kuryloski 6afd459628 Fix an additional dialyzer warning in rabbitmq_web_mqtt 2023-05-26 11:56:48 +02:00
Iliia Khaprov 9dfaa5afb7 If available use user-privded ip address for listener metadata. close #6852 2023-05-25 22:19:49 +02:00
Rin Kuryloski eb94a58bc9 Add a workflow to compare the bazel/erlang.mk output
To catch any drift between the builds
2023-05-15 13:54:14 +02:00
David Ansari 967e262272 Add MQTT client id to connection closed event
As requested in https://github.com/rabbitmq/rabbitmq-server/discussions/6331#discussioncomment-5796154
include all infos that were emitted in the MQTT connection created event also
in the MQTT connection closed event.
This ensures infos such as MQTT client ID are part of the connection
closed event.
Therefore, it's easy for the user to correlate between the two event
types.
Note that the MQTT plugin emits connection created and connection closed events only if
the CONNECT packet was successfully processed, i.e.authentication was successful.

Remove the disconnected_at property because it was never used.
rabbit_event already adds a timestamp to any event.
2023-05-04 09:15:55 +00:00
Michal Kuratczyk 858ed1bff6
Switch to an emqtt fork/branch for OTP26
This change should be reverted once emqx/emqtt is OTP26 compatible.
Our fork/branch isn't either at this point, but at least partially
works. Let's use this branch for now to uncover server-side OTP26
incompatibilities (and continue working on OTP26 support for emqtt of
course).
2023-04-26 11:06:23 +02:00
Rin Kuryloski a944439fba Replace globs in bazel with explicit lists of files
As this is preferred in rules_erlang 3.9.14
2023-04-25 17:29:12 +02:00
Michal Kuratczyk d04b3afe9b verify_none in a couple of tests 2023-04-24 13:11:44 +00:00
Rin Kuryloski 854d01d9a5 Restore the original -include_lib statements from before #6466
since this broke erlang_ls

requires rules_erlang 3.9.13
2023-04-20 12:40:45 +02:00
Michael Klishin c0ed80c625
Merge pull request #6466 from rabbitmq/gazelle
Use gazelle for some maintenance of bazel BUILD files
2023-04-19 09:33:44 +04:00
Rin Kuryloski 8de8f59d47 Use gazelle generated bazel files
Bazel build files are now maintained primarily with `bazel run
gazelle`. This will analyze and merge changes into the build files as
necessitated by certain code changes (e.g. the introduction of new
modules).

In some cases there hints to gazelle in the build files, such as `#
gazelle:erlang...` or `# keep` comments. xref checks on plugins that
depend on the cli are a good example.
2023-04-17 18:13:18 +02:00
Michael Klishin 0f8a5899de
Merge branch 'main' into otp26-compatibility 2023-04-17 14:23:21 +04:00
Rin Kuryloski 8a7eee6a86 Ignore warnings when building plt files for dependencies
As we don't generally care if a dependency has warnings, only the
target
2023-04-17 10:09:24 +02:00
Michal Kuratczyk 9345707739
verify_none in rfc6455_client 2023-04-14 16:15:21 +02:00
David Ansari 0058380fbd Web MQTT: Send CONNACK error code before closing connection
"If the Client supplies a zero-byte ClientId with CleanSession set to 0,
the Server MUST respond to the CONNECT Packet with a CONNACK return code 0x02
(Identifier rejected) and then close the Network Connection" [MQTT-3.1.3-8].

In Web MQTT, the CONNACK was not sent to the client because the Web MQTT
connection process terminated before being sending the CONNACK to the
client.
2023-02-28 10:33:57 +01:00
David Ansari bf2a97a20a Bump emqx/emqtt to 1.8.2 2023-02-21 17:25:19 +01:00
Alexey Lebedeff 949b53543d Fix all dependencies for the dialyzer
This is the latest commit in the series, it fixes (almost) all the
problems with missing and circular dependencies for typing.

The only 2 unsolved problems are:

- `lg` dependency for `rabbit` - the problem is that it's the only
  dependency that contains NIF. And there is no way to make dialyzer
  ignore it - looks like unknown check is not suppressable by dialyzer
  directives. In the future making `lg` a proper dependency can be a
  good thing anyway.

- some missing elixir function in `rabbitmq_cli` (CSV, JSON and
  logging related).

- `eetcd` dependency for `rabbitmq_peer_discovery_etcd` - this one
  uses sub-directories in `src/`, which confuses dialyzer (or our bazel
  machinery is not able to properly handle it). I've tried the latest
  rules_erlang which flattens directory for .beam files, but it wasn't
  enough for dialyzer - it wasn't able to find core erlang files. This
  is a niche plugin and an unusual dependency, so probably not worth
  investigating further.
2023-02-13 17:37:44 +01:00
David Ansari 79c12b60bc Use maybe expression instead of messy patterns
This commit is pure refactoring making the code base more maintainable.

Replace rabbit_misc:pipeline/3 with the new OTP 25 experimental maybe
expression because
"Frequent ways in which people work with sequences of failable
operations include folds over lists of functions, and abusing list
comprehensions. Both patterns have heavy weaknesses that makes them less
than ideal."
https://www.erlang.org/eeps/eep-0049#obsoleting-messy-patterns

Additionally, this commit is more restrictive in the type spec of
rabbit_mqtt_processor state fields.
Specifically, many fields were defined to be `undefined | T` where
`undefined` was only temporarily until the first CONNECT packet was
processed by the processor.
It's better to initialise the MQTT processor upon first CONNECT packet
because there is no point in having a processor without having received
any packet.
This allows many type specs in the processor to change from `undefined |
T` to just `T`.
Additionally, memory is saved by removing the `received_connect_packet`
field from the `rabbit_mqtt_reader` and `rabbit_web_mqtt_handler`.
2023-02-07 16:36:08 +01:00
David Ansari 2d0826c335 Add OAuth 2.0 MQTT system test
Add a test that rabbitmq_auth_backend_oauth2 works with MQTT.

See https://github.com/rabbitmq/rabbitmq-oauth2-tutorial#mqtt-protocol
2023-02-03 14:08:51 +00:00
Chunyi Lyu 6205e5e5e3 MQTT print stacktrace/payload only at debug level 2023-01-31 10:36:08 +00:00
David Ansari cbb389bb2a Remove MQTT processor field peer_addr
as it seems to always match peer_host.

Commit 7e09b85426 adds peer address
provided by WebMQTT plugin.

However, this seems unnecessary since function rabbit_net:peername/1 on
the unwrapped socket provides the same address.

The peer address was the address of the proxy if the proxy protocol is
enabled.

This commit simplifies code and reduces memory consumption.
2023-01-30 12:17:19 +00:00
David Ansari 02cf072ae4 Restrict MQTT CONNECT packet size
In MQTT 3.1.1, the CONNECT packet consists of
1. 10 bytes variable header
2. ClientId (up to 23 bytes must be supported)
3. Will Topic
4. Will Message (maximum length 2^16 bytes)
5. User Name
6. Password

Restricting the CONNECT packet size to 2^16 = 65,536 bytes
seems to be a reasonalbe default.

The value is configurable via the MQTT app parameter
`max_packet_size_unauthenticated`.

(Instead of being called `max_packet_size_connect`) the
name `max_packet_size_unauthenticated` is generic
because MQTT 5 introduces an AUTH packet type.
2023-01-29 15:00:19 +00:00
Chunyi Lyu 209f23fa2f
Revert "Format MQTT code with `erlfmt`" 2023-01-27 18:25:57 +00:00
Chunyi Lyu 1de9fcf582 Format mqtt files with erlfmt 2023-01-27 11:06:41 +00:00
Chunyi Lyu 50e25778bb Adding missing function specs 2023-01-25 19:34:24 +00:00
David Ansari 1f106fcd98 Fix wrong and add missing type specs 2023-01-25 17:13:54 +00:00
David Ansari 9c2f5975ea Support tracing in Native MQTT 2023-01-24 17:32:59 +00:00
David Ansari 9db8626abf Re-enable dialyzer option Wunmatched_returns 2023-01-24 17:32:59 +00:00
David Ansari d4cfbddd35 Parse at most maximum packet length of 256MB
"This allows applications to send Control Packets of size up to
268,435,455 (256 MB)."
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718023
2023-01-24 17:32:59 +00:00
David Ansari a4db85de0d Make pipeline fail when there are dialyzer warnings
We want the build to fail if there are any dialyzer warnings in
rabbitmq_mqtt or rabbitmq_web_mqtt. Otherwise we rely on people manually
executing and checking the results of dialyzer.

Also, we want any test to fail that is flaky.
Flaky tests can indicate subtle errors in either test or program execution.
Instead of marking them as flaky, we should understand and - if possible -
fix the underlying root cause.

Fix OTP 25.0 dialyzer warning

Type gen_server:format_status() is known in OTP 25.2, but not in 25.0
2023-01-24 17:32:59 +00:00
David Ansari fb93a3c17d Block only publishing (Web) MQTT connections
When a cluster wide memory or disk alarm is fired, in AMQP 0.9.1 only
connections that are publishing messages get blocked.
Connections that only consume can continue to empty the queues.

Prior to this commit, all MQTT connections got blocked during a memory
or disk alarm. This has two downsides:
1. MQTT connections that only consume, but never published, cannot empty
   queues anymore.
2. If the memory or disk alarm takes long, the MQTT client does not
   receive a PINGRESP from the server when it sends a PINGREQ potentially
   leading to mass client disconnection (depending on the MQTT client
   implementation).

This commit makes sure that an MQTT connection that never sent a single
PUBLISH packet (e.g. "pure" MQTT subscribers) are not blocked during
memory or disk alarms.

In contrast to AMQP 0.9.1, new connections are still blocked from being
accepted because accepting (many) new MQTT connections also lead to
increased resource usage.

The implemenation as done in this commit is simpler, but also more naive
than the logic in rabbit_reader: rabbit_reader blocks connections more
dynamically whereas rabbit_mqtt_reader and rabbit_web_mqtt_handler
block a connection if the connection ever sent a single PUBLISH packet
during its lifetime.
2023-01-24 17:32:59 +00:00
David Ansari 6ba2dc4afc Switch to Logger macros
Convert from the old rabbit_log* API to the new Logger macros for MQTT
and Web MQTT connections.

Advantages:
* metadata mfa, file, line, pid, gl, time is auto-inserted by Logger.
* Log lines output by the shared module rabbit_mqtt_processor now
  include via the domain whether it's a MQTT or Web MQTT connection.

Instead of using domain [rabbitmq, connection], this commit now uses
the smaller and more specialized domains [rabbitmq, connection, mqtt] and
[rabbitmq, connection, web_mqtt] for MQTT and Web MQTT processes
respectively, resulting in the following example output:
"msg":"Received a CONNECT,", "domain":"rabbitmq.connection.mqtt"
or
"msg":"Received a CONNECT,", "domain":"rabbitmq.connection.web_mqtt"
2023-01-24 17:32:59 +00:00
David Ansari d651f87ea7 Share tests between MQTT and Web MQTT
New test suite deps/rabbitmq_mqtt/test/shared_SUITE contains tests that
are executed against both MQTT and Web MQTT.

This has two major advantages:
1. Eliminates test code duplication between rabbitmq_mqtt and
rabbitmq_web_mqtt making the tests easier to maintain and to understand.
2. Increases test coverage of Web MQTT.

It's acceptable to add a **test** dependency from rabbitmq_mqtt to
rabbitmq_web_mqtt. Obviously, there should be no such dependency
for non-test code.
2023-01-24 17:32:59 +00:00