summaryrefslogtreecommitdiffstats
path: root/src/aclk
diff options
context:
space:
mode:
Diffstat (limited to 'src/aclk')
-rw-r--r--src/aclk/README.md106
-rw-r--r--src/aclk/aclk-schemas/.gitignore11
-rw-r--r--src/aclk/aclk-schemas/.travis.yml4
-rw-r--r--src/aclk/aclk-schemas/LICENSE674
-rw-r--r--src/aclk/aclk-schemas/Makefile74
-rw-r--r--src/aclk/aclk-schemas/README.md2
-rw-r--r--src/aclk/aclk-schemas/buf.yml9
-rw-r--r--src/aclk/aclk-schemas/proto/aclk/v1/lib.proto22
-rw-r--r--src/aclk/aclk-schemas/proto/agent/v1/cmds.proto79
-rw-r--r--src/aclk/aclk-schemas/proto/agent/v1/connection.proto71
-rw-r--r--src/aclk/aclk-schemas/proto/agent/v1/disconnect.proto16
-rw-r--r--src/aclk/aclk-schemas/proto/alarm/v1/config.proto61
-rw-r--r--src/aclk/aclk-schemas/proto/alarm/v1/stream.proto151
-rw-r--r--src/aclk/aclk-schemas/proto/chart/v1/config.proto37
-rw-r--r--src/aclk/aclk-schemas/proto/chart/v1/dimension.proto24
-rw-r--r--src/aclk/aclk-schemas/proto/chart/v1/instance.proto32
-rw-r--r--src/aclk/aclk-schemas/proto/chart/v1/stream.proto86
-rw-r--r--src/aclk/aclk-schemas/proto/context/v1/context.proto57
-rw-r--r--src/aclk/aclk-schemas/proto/context/v1/stream.proto34
-rw-r--r--src/aclk/aclk-schemas/proto/nodeinstance/connection/v1/connection.proto37
-rw-r--r--src/aclk/aclk-schemas/proto/nodeinstance/create/v1/creation.proto32
-rw-r--r--src/aclk/aclk-schemas/proto/nodeinstance/info/v1/info.proto148
-rw-r--r--src/aclk/aclk.c345
-rw-r--r--src/aclk/aclk.h31
-rw-r--r--src/aclk/aclk_alarm_api.c9
-rw-r--r--src/aclk/aclk_alarm_api.h1
-rw-r--r--src/aclk/aclk_capas.c14
-rw-r--r--src/aclk/aclk_capas.h1
-rw-r--r--src/aclk/aclk_otp.c67
-rw-r--r--src/aclk/aclk_proxy.c12
-rw-r--r--src/aclk/aclk_query.c228
-rw-r--r--src/aclk/aclk_query.h29
-rw-r--r--src/aclk/aclk_query_queue.c111
-rw-r--r--src/aclk/aclk_query_queue.h32
-rw-r--r--src/aclk/aclk_rrdhost_state.h11
-rw-r--r--src/aclk/aclk_rx_msgs.c43
-rw-r--r--src/aclk/aclk_rx_msgs.h7
-rw-r--r--src/aclk/aclk_stats.c483
-rw-r--r--src/aclk/aclk_stats.h77
-rw-r--r--src/aclk/aclk_tx_msgs.c85
-rw-r--r--src/aclk/aclk_tx_msgs.h4
-rw-r--r--src/aclk/aclk_util.c66
-rw-r--r--src/aclk/aclk_util.h14
-rw-r--r--src/aclk/helpers/mqtt_wss_pal.h13
-rw-r--r--src/aclk/helpers/ringbuffer_pal.h11
-rw-r--r--src/aclk/https_client.c6
-rw-r--r--src/aclk/https_client.h3
-rw-r--r--src/aclk/mqtt_websockets/.github/workflows/run-tests.yaml14
-rw-r--r--src/aclk/mqtt_websockets/.gitignore10
-rw-r--r--src/aclk/mqtt_websockets/README.md2
-rw-r--r--src/aclk/mqtt_websockets/c-rbuf/cringbuffer.c203
-rw-r--r--src/aclk/mqtt_websockets/c-rbuf/cringbuffer.h47
-rw-r--r--src/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h37
-rw-r--r--src/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c485
-rw-r--r--src/aclk/mqtt_websockets/c_rhash/c_rhash.c264
-rw-r--r--src/aclk/mqtt_websockets/c_rhash/c_rhash.h61
-rw-r--r--src/aclk/mqtt_websockets/c_rhash/c_rhash_internal.h19
-rw-r--r--src/aclk/mqtt_websockets/c_rhash/tests.c273
-rw-r--r--src/aclk/mqtt_websockets/common_internal.h17
-rw-r--r--src/aclk/mqtt_websockets/common_public.h2
-rw-r--r--src/aclk/mqtt_websockets/mqtt_ng.c541
-rw-r--r--src/aclk/mqtt_websockets/mqtt_ng.h10
-rw-r--r--src/aclk/mqtt_websockets/mqtt_wss_client.c360
-rw-r--r--src/aclk/mqtt_websockets/mqtt_wss_client.h54
-rw-r--r--src/aclk/mqtt_websockets/mqtt_wss_log.c130
-rw-r--r--src/aclk/mqtt_websockets/mqtt_wss_log.h39
-rw-r--r--src/aclk/mqtt_websockets/ws_client.c262
-rw-r--r--src/aclk/mqtt_websockets/ws_client.h17
68 files changed, 2441 insertions, 3876 deletions
diff --git a/src/aclk/README.md b/src/aclk/README.md
index 0a260868c..450f9dced 100644
--- a/src/aclk/README.md
+++ b/src/aclk/README.md
@@ -4,13 +4,13 @@ The Agent-Cloud link (ACLK) is the mechanism responsible for securely connecting
through Netdata Cloud. The ACLK establishes an outgoing secure WebSocket (WSS) connection to Netdata Cloud on port
`443`. The ACLK is encrypted, safe, and _is only established if you connect your node_.
-The Cloud App lives at app.netdata.cloud which currently resolves to the following list of IPs:
+The Cloud App lives at app.netdata.cloud which currently resolves to the following list of IPs:
- 54.198.178.11
- 44.207.131.212
-- 44.196.50.41
+- 44.196.50.41
-> ### Caution
+> **Caution**
>
>This list of IPs can change without notice, we strongly advise you to whitelist following domains `app.netdata.cloud`, `mqtt.netdata.cloud`, if this is not an option in your case always verify the current domain resolution (e.g via the `host` command).
@@ -28,106 +28,18 @@ However, to be able to offer the stunning visualizations and advanced functional
## Enable and configure the ACLK
-The ACLK is enabled by default, with its settings automatically configured and stored in the Agent's memory. No file is
-created at `/var/lib/netdata/cloud.d/cloud.conf` until you either connect a node or create it yourself. The default
-configuration uses two settings:
-
-```conf
-[global]
- enabled = yes
- cloud base url = https://app.netdata.cloud
-```
+The ACLK is enabled by default, with its settings automatically configured and stored in the Agent's memory.
If your Agent needs to use a proxy to access the internet, you must [set up a proxy for
-connecting to cloud](/src/claim/README.md#connect-through-a-proxy).
+connecting to cloud](/src/claim/README.md).
You can configure following keys in the `netdata.conf` section `[cloud]`:
-```
+
+```text
[cloud]
- statistics = yes
- query thread count = 2
+ statistics = yes
+ query thread count = 2
```
- `statistics` enables/disables ACLK related statistics and their charts. You can disable this to save some space in the database and slightly reduce memory usage of Netdata Agent.
- `query thread count` specifies the number of threads to process cloud queries. Increasing this setting is useful for nodes with many children (streaming), which can expect to handle more queries (and/or more complicated queries).
-
-## Disable the ACLK
-
-You have two options if you prefer to disable the ACLK and not use Netdata Cloud.
-
-### Disable at installation
-
-You can pass the `--disable-cloud` parameter to the Agent installation when using a kickstart script
-([kickstart.sh](/packaging/installer/methods/kickstart.md), or a [manual installation from
-Git](/packaging/installer/methods/manual.md).
-
-When you pass this parameter, the installer does not download or compile any extra libraries. Once running, the Agent
-kills the thread responsible for the ACLK and connecting behavior, and behaves as though the ACLK, and thus Netdata Cloud,
-does not exist.
-
-### Disable at runtime
-
-You can change a runtime setting in your `cloud.conf` file to disable the ACLK. This setting only stops the Agent from
-attempting any connection via the ACLK, but does not prevent the installer from downloading and compiling the ACLK's
-dependencies.
-
-The file typically exists at `/var/lib/netdata/cloud.d/cloud.conf`, but can change if you set a prefix during
-installation. To disable the ACLK, open that file and change the `enabled` setting to `no`:
-
-```conf
-[global]
- enabled = no
-```
-
-If the file at `/var/lib/netdata/cloud.d/cloud.conf` doesn't exist, you need to create it.
-
-Copy and paste the first two lines from below, which will change your prompt to `cat`.
-
-```bash
-cd /var/lib/netdata/cloud.d
-cat > cloud.conf << EOF
-```
-
-Copy and paste in lines 3-6, and after the final `EOF`, hit **Enter**. The final line must contain only `EOF`. Hit **Enter** again to return to your normal prompt with the newly-created file.
-
-To get your normal prompt back, the final line
-must contain only `EOF`.
-
-```bash
-[global]
- enabled = no
- cloud base url = https://app.netdata.cloud
-EOF
-```
-
-You also need to change the file's permissions. Use `grep "run as user" /etc/netdata/netdata.conf` to figure out which
-user your Agent runs as (typically `netdata`), and replace `netdata:netdata` as shown below if necessary:
-
-```bash
-sudo chmod 0770 cloud.conf
-sudo chown netdata:netdata cloud.conf
-```
-
-Restart your Agent to disable the ACLK.
-
-### Re-enable the ACLK
-
-If you first disable the ACLK and any Cloud functionality and then decide you would like to use Cloud, you must either
-[reinstall Netdata](/packaging/installer/REINSTALL.md) with Cloud enabled or change the runtime setting in your
-`cloud.conf` file.
-
-If you passed `--disable-cloud` to `netdata-installer.sh` during installation, you must
-[reinstall](/packaging/installer/REINSTALL.md) your Agent. Use the same method as before, but pass `--require-cloud` to
-the installer. When installation finishes you can [connect your node](/src/claim/README.md#how-to-connect-a-node).
-
-If you changed the runtime setting in your `var/lib/netdata/cloud.d/cloud.conf` file, edit the file again and change
-`enabled` to `yes`:
-
-```conf
-[global]
- enabled = yes
-```
-
-Restart your Agent and [connect your node](/src/claim/README.md#how-to-connect-a-node).
-
-
diff --git a/src/aclk/aclk-schemas/.gitignore b/src/aclk/aclk-schemas/.gitignore
new file mode 100644
index 000000000..bd495e9a7
--- /dev/null
+++ b/src/aclk/aclk-schemas/.gitignore
@@ -0,0 +1,11 @@
+*.pb.go
+
+#Agent
+*.pb.cc
+*.pb.h
+*.pb.o
+*.pb.Po
+.dirstamp
+
+#Jetbrains
+.idea
diff --git a/src/aclk/aclk-schemas/.travis.yml b/src/aclk/aclk-schemas/.travis.yml
new file mode 100644
index 000000000..7c99550fe
--- /dev/null
+++ b/src/aclk/aclk-schemas/.travis.yml
@@ -0,0 +1,4 @@
+---
+language: minimal
+install: make deps
+script: make CI
diff --git a/src/aclk/aclk-schemas/LICENSE b/src/aclk/aclk-schemas/LICENSE
new file mode 100644
index 000000000..f288702d2
--- /dev/null
+++ b/src/aclk/aclk-schemas/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/src/aclk/aclk-schemas/Makefile b/src/aclk/aclk-schemas/Makefile
new file mode 100644
index 000000000..8f4003070
--- /dev/null
+++ b/src/aclk/aclk-schemas/Makefile
@@ -0,0 +1,74 @@
+SHELL := /usr/bin/env bash -o pipefail
+
+# This controls the location of the cache.
+PROJECT := cloud-schemas
+# This controls the remote HTTPS git location to compare against for breaking changes in CI.
+#
+# Most CI providers only clone the branch under test and to a certain depth, so when
+# running buf check breaking in CI, it is generally preferable to compare against
+# the remote repository directly.
+#
+# Basic authentication is available, see https://buf.build/docs/inputs#https for more details.
+HTTPS_GIT := https://github.com/netdata/cloud-schemas.git
+
+# This controls the version of buf to install and use.
+BUF_VERSION := 0.6.0
+
+### Everything below this line is meant to be static, i.e. only adjust the above variables. ###
+
+UNAME_OS := $(shell uname -s)
+UNAME_ARCH := $(shell uname -m)
+# Buf will be cached to ~/.cache/buf-example.
+CACHE_BASE := $(HOME)/.cache/$(PROJECT)
+# This allows switching between i.e a Docker container and your local setup without overwriting.
+CACHE := $(CACHE_BASE)/$(UNAME_OS)/$(UNAME_ARCH)
+# The location where buf will be installed.
+CACHE_BIN := $(CACHE)/bin
+# Marker files are put into this directory to denote the current version of binaries that are installed.
+CACHE_VERSIONS := $(CACHE)/versions
+
+# Update the $PATH so we can use buf directly
+export PATH := $(abspath $(CACHE_BIN)):$(PATH)
+
+# BUF points to the marker file for the installed version.
+#
+# If BUF_VERSION is changed, the binary will be re-downloaded.
+BUF := $(CACHE_VERSIONS)/buf/$(BUF_VERSION)
+$(BUF):
+ @rm -f $(CACHE_BIN)/buf
+ @mkdir -p $(CACHE_BIN)
+ curl -sSL \
+ "https://github.com/bufbuild/buf/releases/download/v$(BUF_VERSION)/buf-$(UNAME_OS)-$(UNAME_ARCH)" \
+ -o "$(CACHE_BIN)/buf"
+ chmod +x "$(CACHE_BIN)/buf"
+ @rm -rf $(dir $(BUF))
+ @mkdir -p $(dir $(BUF))
+ @touch $(BUF)
+
+.DEFAULT_GOAL := local
+
+# deps allows us to install deps without running any checks.
+
+.PHONY: deps
+deps: $(BUF)
+
+# local is what we run when testing locally.
+# This does breaking change detection against our local git repository.
+
+.PHONY: local
+local: $(BUF)
+ buf check lint ./proto
+ buf check breaking --against '.git#branch=master'
+
+# https is what we run when testing in most CI providers.
+# This does breaking change detection against our git repository.
+
+.PHONY: CI
+CI: $(BUF)
+ buf check lint ./proto
+ buf check breaking --against ".git#branch=master"
+
+.PHONY: clean
+clean:
+ git clean -xdf
+ rm -rf $(CACHE_BASE) \ No newline at end of file
diff --git a/src/aclk/aclk-schemas/README.md b/src/aclk/aclk-schemas/README.md
new file mode 100644
index 000000000..aa6188977
--- /dev/null
+++ b/src/aclk/aclk-schemas/README.md
@@ -0,0 +1,2 @@
+# aclk-schemas
+Protobuf schemas used in ACLK connection
diff --git a/src/aclk/aclk-schemas/buf.yml b/src/aclk/aclk-schemas/buf.yml
new file mode 100644
index 000000000..532053d91
--- /dev/null
+++ b/src/aclk/aclk-schemas/buf.yml
@@ -0,0 +1,9 @@
+build:
+ roots:
+ - proto
+lint:
+ use:
+ - DEFAULT
+breaking:
+ use:
+ - FILE
diff --git a/src/aclk/aclk-schemas/proto/aclk/v1/lib.proto b/src/aclk/aclk-schemas/proto/aclk/v1/lib.proto
new file mode 100644
index 000000000..f32c32c6e
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/aclk/v1/lib.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+package aclk_lib.v1;
+
+import "google/protobuf/timestamp.proto";
+
+option go_package = "aclk_lib/v1;aclklib";
+
+// ACLKMessagePosition is used by sequenced messages to define their exact position
+message ACLKMessagePosition {
+ uint64 sequence_id = 1;
+ // auto generated in Agent's DB upon sequence_id creation
+ google.protobuf.Timestamp seq_id_created_at = 2;
+ uint64 previous_sequence_id = 3;
+}
+
+message Capability {
+ string name = 1;
+ uint32 version = 2;
+ // version == 0 is equivalent to not having the capability at all
+ bool enabled = 3;
+}
diff --git a/src/aclk/aclk-schemas/proto/agent/v1/cmds.proto b/src/aclk/aclk-schemas/proto/agent/v1/cmds.proto
new file mode 100644
index 000000000..c37c00c3a
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/agent/v1/cmds.proto
@@ -0,0 +1,79 @@
+syntax = "proto3";
+option go_package = "agent/v1;agent";
+
+package agent.v1;
+
+import "google/protobuf/timestamp.proto";
+import "proto/aclk/v1/lib.proto";
+
+message CancelPendingRequest {
+ // must match the ID sent with the request originally made
+ // other than this agent will not put conditions on it
+ // and will treat it as opaque string (it simply has to match)
+ // However this doesn't mean there are no conditions on the id
+ // made on the request side
+ string request_id = 1;
+
+ // time when the cancellation request was generated
+ google.protobuf.Timestamp timestamp = 2;
+
+ // optional might be useful for debugging purposes
+ string trace_id = 3;
+}
+
+// AgentCommand is sent from the Cloud to the Agent at `/agent/{claim_id}/inbound/v1/cmd/AgentCommand`
+// the message includes the resource that the Cloud needs to GET from the Agent HTTP API along with related metadata
+message AgentCommand {
+ // the topic to which the Cloud awaits for the AgentCommandResponse.
+ // example: `/svc/agent-data-ctrl/2d7b7edd-561e-4aec-8ac1-466a585520f5/resp`
+ string callback_topic = 1;
+ // the topic to which the Cloud awaits for the AgentCommandAck.
+ // example: `/svc/agent-data-ctrl/2d7b7edd-561e-4aec-8ac1-466a585520f5/resp`
+ string ack_topic = 2;
+ // unique identifier for the AgentCommand
+ // example: `617038b3-7c2a-4617-a78f-ab37bd820198`
+ string message_id = 3;
+ // defined in milliseconds, the time the Agent has to respond before Cloud
+ // considering the request as timed-out
+ // example: `60000`
+ uint64 timeout = 4;
+ // defined in milliseconds, the time the Agent has to send back to the Cloud
+ // an AgentCommandAck message signaling that is still working on the request
+ // example: `3000`
+ uint64 ack_timeout = 5;
+ // the requested Agent resource
+ // example: `/api/v2/data?query_params_go_here`
+ string resource = 6;
+}
+
+// AgentCommandAck is sent from the Agent to the Cloud at predefined intervals (`AgentCommand.ack_timeout`) to predefined topic (`AgentCommand.ack_topic`)
+// signaling that the Agent is still working to serve an AgentCommand (referenced by the message_id) that the Cloud sent
+message AgentCommandAck {
+ // unique identifier to reference AgentCommand on which the Agent is still working on serving
+ // example: `617038b3-7c2a-4617-a78f-ab37bd820198`
+ string message_id = 1;
+ // the timestamp when the Agent created this AgentCommandAck message
+ google.protobuf.Timestamp created_at = 2;
+ // integer revealing the progress of completion to serve the AgentCommand with the given message_id
+ // example: `25`
+ uint32 progress_percent = 3;
+}
+
+// AgentCommandResponse is sent from the Agent to the Cloud at `/agent/{claim_id}/inbound/v1/cmd/AgentCommand`
+// the message includes the resource that the Cloud needs to GET from the Agent HTTP API along with related metadata
+message AgentCommandResponse {
+ // unique identifier for the AgentCommand
+ // example: `617038b3-7c2a-4617-a78f-ab37bd820198`
+ string message_id = 1;
+ // the (http) status code of the Agent's API response
+ // example: `200`
+ uint32 status_code = 2;
+ // the dumped raw (http) response the Agent's API returned
+ bytes response = 3;
+ // the Agent's timestamp (aka legacy `timestamp`)
+ google.protobuf.Timestamp timestamp = 4;
+ // the timestamp when the Agent received the AgentCommand for execution (aka legacy `t-rx`)
+ google.protobuf.Timestamp received_at = 5;
+ // the amount of microseconds the Agent needed to execute the HTTP request of the AgentCommand (aka legacy`t-exec`)
+ uint64 exec_time = 6;
+}
diff --git a/src/aclk/aclk-schemas/proto/agent/v1/connection.proto b/src/aclk/aclk-schemas/proto/agent/v1/connection.proto
new file mode 100644
index 000000000..a792214ff
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/agent/v1/connection.proto
@@ -0,0 +1,71 @@
+syntax = "proto3";
+option go_package = "agent/v1;agent";
+
+package agent.v1;
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+import "proto/aclk/v1/lib.proto";
+
+message UpdateAgentConnection {
+ string claim_id = 1;
+ bool reachable = 2;
+
+ int64 session_id = 3;
+
+ ConnectionUpdateSource update_source = 4;
+
+ // mqtt_broker_addr shard to use for reaching the agent
+ // cloud injects this information
+ string mqtt_broker_addr = 5;
+
+ google.protobuf.Timestamp updated_at = 6;
+
+ // vmq_instance_id broker shard to use for reaching the agent
+ // cloud injects this information
+ int32 vmq_instance_id = 7;
+
+ // > 15 optional fields:
+ // How long the system was running until connection (only applicable when reachable=true)
+ google.protobuf.Duration system_uptime = 15;
+
+ // How long the netdata agent was running until connection (only applicable when reachable=true)
+ google.protobuf.Duration agent_uptime = 16;
+
+ repeated aclk_lib.v1.Capability capabilities = 17;
+}
+
+message SendNodeInstances {
+ string claim_id = 1;
+ Config config = 2;
+ // The ID of the space where this agent is claimed.
+ string space_id = 3;
+}
+
+// ConnectionUpdateSource is to determine whether the connection update was issued
+enum ConnectionUpdateSource {
+ // CONNECTION_UPDATE_SOURCE_UNSPECIFIED acts as default value for protobuf and is never specified
+ CONNECTION_UPDATE_SOURCE_UNSPECIFIED = 0;
+ // CONNECTION_UPDATE_SOURCE_AGENT A direct message from an agent
+ CONNECTION_UPDATE_SOURCE_AGENT = 1;
+ // CONNECTION_UPDATE_SOURCE_LWT message delivered as the Last Will and Testiment from MQTT broker if an agent connection with the broker is lost
+ CONNECTION_UPDATE_SOURCE_LWT = 2;
+ // CONNECTION_UPDATE_SOURCE_HEURISTIC A cloud generated message to sanitize incorrect internal state
+ CONNECTION_UPDATE_SOURCE_HEURISTIC = 3;
+}
+
+message AgentConfig {
+ string dashboards = 1;
+ string alert_notifications = 2;
+}
+
+message CloudConfig {
+ string dashboards = 1;
+ string alert_notifications = 2;
+}
+
+message Config {
+ reserved 1 to 3;
+ AgentConfig agent_config = 4;
+ CloudConfig cloud_config = 5;
+}
diff --git a/src/aclk/aclk-schemas/proto/agent/v1/disconnect.proto b/src/aclk/aclk-schemas/proto/agent/v1/disconnect.proto
new file mode 100644
index 000000000..852ef702a
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/agent/v1/disconnect.proto
@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package agent.v1;
+
+import "google/protobuf/timestamp.proto";
+
+option go_package = "agent/v1;agent";
+
+// Sent by Cloud to instruct Agent to disconnect ASAP
+message DisconnectReq {
+ uint64 reconnect_after_seconds = 1;
+ bool permaban = 2;
+ google.protobuf.Timestamp created_at = 3;
+ uint32 error_code = 4;
+ string error_description = 5;
+}
diff --git a/src/aclk/aclk-schemas/proto/alarm/v1/config.proto b/src/aclk/aclk-schemas/proto/alarm/v1/config.proto
new file mode 100644
index 000000000..97050fecd
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/alarm/v1/config.proto
@@ -0,0 +1,61 @@
+syntax = "proto3";
+
+package alarms.v1;
+
+option go_package = "alarms/v1;alarms";
+
+message SendAlarmConfiguration{
+ string config_hash = 1;
+}
+
+message ProvideAlarmConfiguration {
+ string config_hash = 1;
+ AlarmConfiguration config = 2;
+}
+
+message AlarmConfiguration{
+ string alarm = 1;
+ string template = 2;
+ string on_chart = 3;
+
+ string classification = 4;
+ string type = 5;
+ string component = 6;
+
+ string os = 7;
+ string hosts = 8;
+ string plugin = 9;
+ string module = 10;
+ string charts = 11;
+ string families = 12 [deprecated=true];
+ string lookup = 13;
+ string every = 14;
+ string units = 15;
+
+ string green = 16;
+ string red = 17;
+
+ string calculation_expr = 18;
+ string warning_expr = 19;
+ string critical_expr = 20;
+
+ string recipient = 21;
+ string exec = 22;
+ string delay = 23;
+ string repeat = 24;
+ string info = 25;
+ string options = 26;
+ string host_labels = 27;
+
+ //parsed values from above config values
+ //indicated by p_
+ int32 p_db_lookup_after = 28;
+ int32 p_db_lookup_before = 29;
+ string p_db_lookup_dimensions = 30;
+ string p_db_lookup_method = 31;
+ string p_db_lookup_options = 32;
+ int32 p_update_every = 33;
+
+ string chart_labels = 34;
+ string summary = 35;
+}
diff --git a/src/aclk/aclk-schemas/proto/alarm/v1/stream.proto b/src/aclk/aclk-schemas/proto/alarm/v1/stream.proto
new file mode 100644
index 000000000..f782becdc
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/alarm/v1/stream.proto
@@ -0,0 +1,151 @@
+syntax = "proto3";
+
+package alarms.v1;
+
+import "google/protobuf/timestamp.proto";
+
+option go_package = "alarms/v1;alarms";
+
+message SendAlarmLogHealth {
+ string node_id = 1;
+}
+
+message AlarmLogHealth {
+ string claim_id = 1;
+ string node_id = 2;
+ bool enabled = 3;
+ AlarmLogStatus status = 4;
+ LogEntries log_entries = 5;
+}
+
+message LogEntries {
+ int64 first_sequence_id = 1;
+ google.protobuf.Timestamp first_when = 2;
+
+ int64 last_sequence_id = 3;
+ google.protobuf.Timestamp last_when = 4;
+}
+
+enum AlarmLogStatus {
+ ALARM_LOG_STATUS_UNSPECIFIED = 0;
+ ALARM_LOG_STATUS_RUNNING = 1;
+ ALARM_LOG_STATUS_IDLE = 2;
+}
+
+message StartAlarmStreaming {
+ string node_id = 1;
+ uint64 batch_id = 2 [deprecated=true];
+ uint64 start_sequnce_id = 3 [deprecated=true];
+ // Instructs the agent to sync all configured alarms
+ bool resets = 4;
+ uint64 version = 5;
+}
+
+message SendAlarmCheckpoint {
+ string node_id = 1;
+ string claim_id = 2;
+ uint64 version = 3;
+}
+
+message AlarmCheckpoint {
+ string node_id = 1;
+ string claim_id = 2;
+ bytes checksum = 3;
+}
+
+message AlarmLogEntry {
+ string node_id = 1;
+ string claim_id = 2;
+
+ // The chart's id field
+ string chart = 3;
+ string name = 4;
+ string family = 5 [deprecated=true];
+ uint64 batch_id = 6 [deprecated=true];
+ uint64 sequence_id = 7 [deprecated=true];
+ uint64 when = 8;
+
+ string config_hash = 9;
+
+ int32 utc_offset = 10;
+ string timezone = 11;
+
+ // Paths that can be custom for the same alarm, but depend on installation path for each user. Should be here or in config ?
+ string exec_path = 12;
+ string conf_source = 13;
+ string command = 14;
+
+ // In seconds, uint32 is safe ?
+ uint32 duration = 15;
+ uint32 non_clear_duration = 16;
+
+ AlarmStatus status = 17;
+ AlarmStatus old_status = 18;
+ uint64 delay = 19;
+ uint64 delay_up_to_timestamp = 20;
+ // Todo: verify that we need these. sequence_id doesn't suffice?
+ // uint64 updated_by_id = 12;
+ // uint64 updates_id = 13;
+ uint64 last_repeat = 21;
+ bool silenced = 22;
+
+ // Check if string values are needed
+ string value_string = 23;
+ string old_value_string = 24;
+
+ double value = 25;
+ double old_value = 26;
+
+ // Updated alarm entry, when the status of the alarm has been updated by a later entry
+ bool updated = 27;
+
+ // Rendered_info
+ string rendered_info = 28;
+
+ // The chart's context field
+ string chart_context = 29;
+
+ // Counter of alert transitions for this alert chain
+ uint64 event_id = 30;
+
+ // A unique uuid for this alert event
+ string transition_id = 31;
+
+ // The chart's name field
+ string chart_name = 32;
+
+ // The rendered summary
+ string summary = 33;
+ uint64 alert_version = 34;
+}
+
+enum AlarmStatus {
+ ALARM_STATUS_NULL = 0;
+ ALARM_STATUS_UNKNOWN = 1;
+ ALARM_STATUS_REMOVED = 2;
+ ALARM_STATUS_NOT_A_NUMBER = 3;
+ ALARM_STATUS_CLEAR = 4;
+ ALARM_STATUS_WARNING = 5;
+ ALARM_STATUS_CRITICAL = 6;
+}
+
+// SendAlarmSnapshot: send from cloud to the agent, to initiate an AlarmSnapshot image of current alarms back to the cloud
+message SendAlarmSnapshot {
+ string node_id = 1;
+ string claim_id = 2;
+ uint64 snapshot_id = 3 [deprecated=true];
+ uint64 sequence_id = 4 [deprecated=true];
+ string snapshot_uuid = 5;
+}
+
+// Agent responds with AlarmSnapshot to a SendAlarmSnapshot message
+message AlarmSnapshot{
+ string node_id = 1;
+ string claim_id = 2;
+ uint64 snapshot_id = 3 [deprecated=true]; // Same id from SendAlarmSnapshot message
+ uint32 chunks = 4; // In case full snapshot can not fit in a single message, indicates the total number of messages for this snapshot_id
+ uint32 chunk_size = 5; // How many alerts this chunk contains
+ uint32 chunk = 6; // Chunk index of this message
+ repeated AlarmLogEntry alarms = 7; // a list of AlarmLogEntry's
+ string snapshot_uuid = 8;
+}
diff --git a/src/aclk/aclk-schemas/proto/chart/v1/config.proto b/src/aclk/aclk-schemas/proto/chart/v1/config.proto
new file mode 100644
index 000000000..f0c5e3a35
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/chart/v1/config.proto
@@ -0,0 +1,37 @@
+syntax = "proto3";
+
+package chart.v1;
+
+option go_package = "chart/config/v1;chartconfig";
+
+// UpdateChartConfigs command contains the list of missing chart configs from the cloud to agent
+message UpdateChartConfigs {
+ // claim_id, node_id pair is used to identify the Node Instance
+ string claim_id = 1;
+ string node_id = 2;
+ // list of config hashes missing from cloud and requested from the agent
+ repeated string config_hashes = 3;
+}
+
+message ChartConfigsUpdated {
+ repeated ChartConfigUpdated configs = 1;
+}
+
+message ChartConfigUpdated {
+ string type = 1;
+ string family = 2;
+ string context = 3;
+ string title = 4;
+ uint64 priority = 5;
+ string plugin = 6;
+ string module = 7;
+ ChartType chart_type = 8;
+ string units = 9;
+ string config_hash = 10;
+}
+
+enum ChartType {
+ LINE = 0;
+ AREA = 1;
+ STACKED = 2;
+}
diff --git a/src/aclk/aclk-schemas/proto/chart/v1/dimension.proto b/src/aclk/aclk-schemas/proto/chart/v1/dimension.proto
new file mode 100644
index 000000000..8bcb564b8
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/chart/v1/dimension.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+package chart.v1;
+
+import "google/protobuf/timestamp.proto";
+
+import "proto/aclk/v1/lib.proto";
+
+option go_package = "chart/dimension/v1;chartdimension";
+
+// ChartDimensionUpdated is a single event sent from the Agent to the Cloud containing chart dimension data.
+//
+// ChartDimensionUpdated messages are dispatched in bulk to the Cloud wrapped in ChartsAndDimensionsUpdated messages.
+message ChartDimensionUpdated {
+ string id = 1;
+ string chart_id = 2;
+ string node_id = 3;
+ string claim_id = 4;
+ string name = 5;
+ google.protobuf.Timestamp created_at = 6;
+ // null value means that the dimension is currently collected (live)
+ google.protobuf.Timestamp last_timestamp = 7;
+ aclk_lib.v1.ACLKMessagePosition position = 8;
+}
diff --git a/src/aclk/aclk-schemas/proto/chart/v1/instance.proto b/src/aclk/aclk-schemas/proto/chart/v1/instance.proto
new file mode 100644
index 000000000..25c99e7c7
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/chart/v1/instance.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+
+package chart.v1;
+
+import "proto/aclk/v1/lib.proto";
+
+option go_package = "chart/instance/v1;chartinstance";
+
+// ChartInstanceUpdated is a single event sent from the Agent to the Cloud containing chart instance data.
+//
+// ChartInstanceUpdated messages are dispatched in bulk to the Cloud wrapped in ChartsAndDimensionsUpdated messages.
+message ChartInstanceUpdated {
+ string id = 1;
+ string claim_id = 2;
+ string node_id = 3;
+ string name = 4;
+ map<string, string> chart_labels = 5;
+ MemoryMode memory_mode = 6;
+ // in seconds
+ uint32 update_every_interval = 7;
+ string config_hash = 8;
+ aclk_lib.v1.ACLKMessagePosition position = 9;
+}
+
+enum MemoryMode {
+ NONE = 0;
+ RAM = 1;
+ MAP = 2;
+ SAVE = 3;
+ ALLOC = 4;
+ DB_ENGINE = 5;
+}
diff --git a/src/aclk/aclk-schemas/proto/chart/v1/stream.proto b/src/aclk/aclk-schemas/proto/chart/v1/stream.proto
new file mode 100644
index 000000000..9473538f2
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/chart/v1/stream.proto
@@ -0,0 +1,86 @@
+syntax = "proto3";
+
+package chart.v1;
+
+import "google/protobuf/timestamp.proto";
+
+import "proto/chart/v1/instance.proto";
+import "proto/chart/v1/dimension.proto";
+
+option go_package = "chart/stream/v1;chartstream";
+
+// StreamChartsAndDimensions is a Command produced by the Cloud, consumed by the Agent.
+//
+// It instructs the Agent to start sending ChartsAndDimensionsUpdated messages for a NodeInstance
+// after the last sequence_id that the Cloud has successfully ingested.
+message StreamChartsAndDimensions {
+ // claim_id, node_id pair is used to identify the Node Instance
+ string claim_id = 1;
+ string node_id = 2;
+
+ // sequence_id last verified sequence sent by the Agent
+ uint64 sequence_id = 3;
+ // batch_id identifies the stream_id and gets incremented every time the Cloud sends a new StreamChartsAndDimensions command
+ uint64 batch_id = 4;
+ // seq_id_created_at autogenerated timestamp in Agent's DB upon sequence_id creation
+ google.protobuf.Timestamp seq_id_created_at = 5;
+}
+
+
+// ChartsAndDimensionsAck is an Event produced by the Cloud, consumed by the Agent.
+//
+// This Event is an acknowledgment from the Cloud side that Chart messages up to a specific last_sequence_id
+// have been successfully ingested, and could be potentially deleted from the Agent's DB.
+message ChartsAndDimensionsAck {
+ string claim_id = 1;
+ string node_id = 2;
+ // the last verified stored message's seq_id
+ uint64 last_sequence_id = 3;
+}
+
+// ResetChartMessages is a Command produced by the Agent, consumed by the Cloud.
+//
+// This Command instructs the Cloud to clear its Chart state for a specific NodeInstance and re-sync
+// because of a ResetReason.
+message ResetChartMessages {
+ // claim_id, node_id pair is used to identify the Node Instance
+ string claim_id = 1;
+ string node_id = 2;
+
+ ResetReason reason = 3;
+}
+
+enum ResetReason {
+ DB_EMPTY = 0;
+ SEQ_ID_NOT_EXISTS = 1;
+ TIMESTAMP_MISMATCH = 2;
+}
+
+// ChartsAndDimensionsUpdated is a wrapper Event (`fat` message) produced by the Agent, consumed by the Cloud.
+//
+// It potentially includes a collection of ChartInstanceUpdated messages and|or a collection of ChartDimensionUpdated messages.
+message ChartsAndDimensionsUpdated {
+ repeated chart.v1.ChartInstanceUpdated charts = 1;
+ repeated chart.v1.ChartDimensionUpdated dimensions = 2;
+ uint64 batch_id = 3;
+}
+
+// RetentionUpdated includes the available retentions (in seconds) of the dimensions - of a specific node instance and memory-mode -
+// on a per update_every level.
+// This message is sent over upon Agent Database rotation events to inform the Cloud in total about the newly updated data retentions
+// of a node instance's dimensions.
+message RetentionUpdated {
+ // claim_id, node_id pair is used to identify the Node Instance
+ string claim_id = 1;
+ string node_id = 2;
+ // the memory_mode used by the node instance's chart instances
+ chart.v1.MemoryMode memory_mode = 3;
+ // this mapping identifies the newly updated available retention (in seconds) of the node instance's dimensions
+ // the keys are the update_every categories of various dimensions (1, 2, 4, 10 etc.),
+ // and the values are the available retention (in seconds) of each dimension belonging to the update_every category
+ // denoted by the key
+ map<uint32, uint32> interval_durations = 4;
+ // the timestamp when the db rotation event took place. Can be used in conjunction with the interval_durations
+ // to compute the beginning of each `updated_every` group's retention
+ google.protobuf.Timestamp rotation_timestamp = 5;
+}
diff --git a/src/aclk/aclk-schemas/proto/context/v1/context.proto b/src/aclk/aclk-schemas/proto/context/v1/context.proto
new file mode 100644
index 000000000..eb771f8eb
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/context/v1/context.proto
@@ -0,0 +1,57 @@
+syntax = "proto3";
+
+package context.v1;
+
+option go_package = "context/v1;context";
+
+// ContextsUpdated is an Event produced by the Agent, consumed by the Cloud.
+//
+// it contains a collection of ContextUpdated messages for a specific NodeInstance.
+message ContextsUpdated {
+ // contexUpdates contains the collection of context updates
+ repeated ContextUpdated contextUpdates = 1;
+ // claim_id, node_id pair identifies the node instance
+ string claim_id = 2;
+ string node_id = 3;
+ // version_hash is the contexts version_hash result the cloud should
+ // get after applying this message updates.
+ uint64 version_hash = 4;
+ // it's and always increasing number to compare
+ // which version_hash is more recent between multiple
+ // ContextsUpdated messages. Bigger means more recent.
+ uint64 created_at = 5;
+}
+
+// ContextUpdated contains context data.
+message ContextUpdated {
+ // context id
+ string id = 1;
+ // context version is an epoch in seconds.
+ uint64 version = 2;
+ // first_entry, last_entry are epochs in seconds
+ uint64 first_entry = 3;
+ uint64 last_entry = 4;
+ // deleted flag is used to signal a context deletion
+ bool deleted = 5;
+ // context configuration fields
+ string title = 6;
+ uint64 priority = 7;
+ string chart_type = 8;
+ string units = 9;
+ string family = 10;
+}
+
+// ContextsSnapshot is an Event produced by the Agent, consumed by the Cloud.
+//
+// it contains a snapshot of the existing contexts on the Agent.
+// snapshot version and context versions are epochs in seconds so we can
+// identify if a context version was generated after a specific snapshot.
+message ContextsSnapshot {
+ // contexts contains the collection of existing contexts
+ repeated ContextUpdated contexts = 1;
+ // claim_id, node_id pair identifies the node instance
+ string claim_id = 2;
+ string node_id = 3;
+ // version is an epoch in seconds
+ uint64 version = 4;
+}
diff --git a/src/aclk/aclk-schemas/proto/context/v1/stream.proto b/src/aclk/aclk-schemas/proto/context/v1/stream.proto
new file mode 100644
index 000000000..a6e7e3abf
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/context/v1/stream.proto
@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+package context.v1;
+
+option go_package = "context/v1;context";
+
+// ContextsCheckpoint is a Command produced by the Cloud, consumed by the Agent.
+//
+// It informs the Agent the contexts' version_hash that the cloud has for a specific NodeInstance.
+message ContextsCheckpoint {
+ // claim_id, node_id pair is used to identify the NodeInstance.
+ string claim_id = 1;
+ string node_id = 2;
+ // version_hash tells the Agent the current version hash for the contexts received
+ // if the version hash calculated by the Agent is different, Agent will request
+ // to re-sync all contexts.
+ uint64 version_hash= 3;
+}
+
+// StopStreamingContexts is a Command produced by the Cloud, consumed by the Agent.
+//
+// It instructs the Agent to stop sending ContextsUpdated messages for a NodeInstance
+// due to a reason.
+message StopStreamingContexts {
+ // claim_id, node_id pair is used to identify the node instance
+ string claim_id = 1;
+ string node_id = 2;
+
+ StopStreamingContextsReason reason = 3;
+}
+
+enum StopStreamingContextsReason {
+ RATE_LIMIT_EXCEEDED = 0;
+}
diff --git a/src/aclk/aclk-schemas/proto/nodeinstance/connection/v1/connection.proto b/src/aclk/aclk-schemas/proto/nodeinstance/connection/v1/connection.proto
new file mode 100644
index 000000000..f0c02461e
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/nodeinstance/connection/v1/connection.proto
@@ -0,0 +1,37 @@
+syntax = "proto3";
+option go_package = "nodeinstance/connection/v1;nodeinstanceconnection";
+
+package nodeinstance.v1;
+
+import "google/protobuf/timestamp.proto";
+import "proto/aclk/v1/lib.proto";
+
+message UpdateNodeInstanceConnection {
+ string claim_id = 1;
+ string node_id = 2;
+
+ // liveness whether node data are actively streamed to the agent.
+ bool liveness = 3;
+
+ // queryable whether the agent has data about the node.
+ bool queryable = 4;
+
+ int64 session_id = 5;
+
+ google.protobuf.Timestamp updated_at = 6;
+
+ // mqtt_broker_addr shard to use for reaching the agent
+ // cloud injects this information.
+ string mqtt_broker_addr = 7;
+
+ // vmq_instance_id broker shard to use for reaching the agent
+ // cloud injects this information.
+ int32 vmq_instance_id = 8;
+
+ // hops is the number of streaming hops between collection of node data
+ // and the claimed agent. Zero if no streaming is involved.
+ int32 hops = 9;
+
+ // capabilities of node instance NOT the NODE or agent!!!
+ repeated aclk_lib.v1.Capability capabilities = 10;
+}
diff --git a/src/aclk/aclk-schemas/proto/nodeinstance/create/v1/creation.proto b/src/aclk/aclk-schemas/proto/nodeinstance/create/v1/creation.proto
new file mode 100644
index 000000000..922337154
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/nodeinstance/create/v1/creation.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+option go_package = "node_instance/creation/v1;node_instancecreation";
+
+package nodeinstance.create.v1;
+
+message CreateNodeInstance {
+ // Claim ID of the Agent the Node Instance belongs to.
+ // Eventually, the NodeInstance will be identified by the compilation of
+ // this claim_id and NodeID returned by `CreateNodeInstanceResult`
+ string claim_id = 1;
+ // Machine GUID of the Machine the request comes from
+ // Used to look for an existing NodeID in the space claim_id belongs to
+ string machine_guid = 2;
+ string hostname = 3;
+
+ // vmq_instance_id broker shard to use for reaching the agent
+ // cloud injects this information.
+ int32 vmq_instance_id = 4;
+ // mqtt_broker_addr shard to use for reaching the agent
+ // cloud injects this information.
+ string mqtt_broker_addr = 5;
+
+ // hops is the number of streaming hops between collection of node data
+ // and the claimed agent. Zero if no streaming is involved.
+ int32 hops = 6;
+}
+
+message CreateNodeInstanceResult {
+ string node_id = 1;
+ string machine_guid = 2;
+}
+
diff --git a/src/aclk/aclk-schemas/proto/nodeinstance/info/v1/info.proto b/src/aclk/aclk-schemas/proto/nodeinstance/info/v1/info.proto
new file mode 100644
index 000000000..7aa9d0448
--- /dev/null
+++ b/src/aclk/aclk-schemas/proto/nodeinstance/info/v1/info.proto
@@ -0,0 +1,148 @@
+syntax = "proto3";
+option go_package = "node_instance/info/v1;nodeinstanceinfo";
+
+package nodeinstance.info.v1;
+
+import "google/protobuf/timestamp.proto";
+import "proto/aclk/v1/lib.proto";
+
+// UpdateNodeInfo (Command)
+//
+// pulsar topic: `UpdateNodeInfo` (sharded)
+//
+// key: `claim_id,node_id`
+//
+// Publishers: `netdata/agent`
+// Subscribers: `cloud-node-mqtt-output-service`
+//
+// When:
+// On nodeinstance connect
+//
+message UpdateNodeInfo {
+ string node_id = 7;
+
+ string claim_id = 1;
+
+ NodeInfo data = 2;
+ // to be obsoleted in future
+ // all new fields should go into node_info
+ // or node_instance_info respectively
+
+ google.protobuf.Timestamp updated_at = 3;
+
+ int64 session_id = 4;
+
+ string machine_guid = 5;
+
+ bool child = 6;
+
+ MachineLearningInfo ml_info = 8;
+ // to be obsoleted in far future
+
+ NodeInfo2 node_info = 9;
+ // node_info shows data about actual node
+ // for example feature (ml) for this
+ // node (child) might be available/enabled on the node (child) directly
+ // but not available trough the parent (node_instance)
+
+ NodeInstanceInfo node_instance_info = 10;
+ // info specific to the node_instance for this node available trough agent
+ // who sends this message.
+ // e.g. machine learning is enabled for this node and processing is done
+ // by the actual agent (parent). (child itself might or might not be
+ // ml ml_capable by itself (see node_info))
+}
+
+message NodeInfo2 {
+ repeated aclk_lib.v1.Capability capabilities = 1;
+}
+
+message NodeInstanceInfo {
+ repeated aclk_lib.v1.Capability capabilities = 1;
+}
+
+// NodeInfo describes the metadata of a node
+message NodeInfo {
+ string name = 1;
+
+ string os = 2;
+ string os_name = 3;
+ string os_version = 4;
+
+ string kernel_name = 5;
+ string kernel_version = 6;
+
+ string architecture = 7;
+
+ // number of cpu cores in the node
+ uint32 cpus = 8;
+
+ // human readable (value + unit) frequency of cpu
+ string cpu_frequency = 9;
+
+ // human readable (value + unit) size of node's memory
+ string memory = 10;
+
+ // human readable (value + unit) size of all (sum) node's disks
+ string disk_space = 11;
+
+ // version of the netdata agent
+ string version = 12;
+
+ // release channel of netdata agent (example: nightly)
+ string release_channel = 13;
+
+ string timezone = 14;
+
+ // virtualization_type example: kvm (optional)
+ string virtualization_type = 15;
+
+ // container_type example: docker (optional)
+ string container_type = 16;
+
+ string custom_info = 17;
+
+ // [Obsolete] repeated string services = 18;
+ reserved 18;
+
+ string machine_guid = 19;
+
+ // [Obsolete] repeated MirroredHostStatus mirrored_hosts_status = 20;
+ reserved 20;
+
+ map<string, string> host_labels = 21;
+
+ MachineLearningInfo ml_info = 22;
+
+ // [Obsolete] repeated string collectors = 23;
+ reserved 23;
+}
+
+message MachineLearningInfo {
+ // have ML capability
+ bool ml_capable = 1;
+
+ // runs ML functionality
+ bool ml_enabled = 2;
+}
+
+// UpdateNodeCollectors (Command)
+//
+// key: `claim_id,node_id`
+//
+// Publishers: `netdata/agent`
+//
+// When:
+// On nodeinstance connect (after agent settles) and on detection of change of collectors
+//
+
+message CollectorInfo {
+ string module = 1;
+ string plugin = 2;
+}
+
+message UpdateNodeCollectors {
+ string claim_id = 1;
+ string node_id = 2;
+ repeated CollectorInfo collectors = 3;
+}
diff --git a/src/aclk/aclk.c b/src/aclk/aclk.c
index 389d7455f..7bc620a61 100644
--- a/src/aclk/aclk.c
+++ b/src/aclk/aclk.c
@@ -2,8 +2,6 @@
#include "aclk.h"
-#ifdef ENABLE_ACLK
-#include "aclk_stats.h"
#include "mqtt_websockets/mqtt_wss_client.h"
#include "aclk_otp.h"
#include "aclk_tx_msgs.h"
@@ -14,7 +12,6 @@
#include "https_client.h"
#include "schema-wrappers/schema_wrappers.h"
#include "aclk_capas.h"
-
#include "aclk_proxy.h"
#ifdef ACLK_LOG_CONVERSATION_DIR
@@ -23,20 +20,38 @@
#include <fcntl.h>
#endif
-#define ACLK_STABLE_TIMEOUT 3 // Minimum delay to mark AGENT as stable
-
-#endif /* ENABLE_ACLK */
-
int aclk_pubacks_per_conn = 0; // How many PubAcks we got since MQTT conn est.
int aclk_rcvd_cloud_msgs = 0;
int aclk_connection_counter = 0;
-int disconnect_req = 0;
-int aclk_connected = 0;
+static bool aclk_connected = false;
+static inline void aclk_set_connected(void) {
+ __atomic_store_n(&aclk_connected, true, __ATOMIC_RELAXED);
+}
+static inline void aclk_set_disconnected(void) {
+ __atomic_store_n(&aclk_connected, false, __ATOMIC_RELAXED);
+}
+
+inline bool aclk_online(void) {
+ return __atomic_load_n(&aclk_connected, __ATOMIC_RELAXED);
+}
+
+bool aclk_online_for_contexts(void) {
+ return aclk_online() && aclk_query_scope_has(HTTP_ACL_METRICS);
+}
+
+bool aclk_online_for_alerts(void) {
+ return aclk_online() && aclk_query_scope_has(HTTP_ACL_ALERTS);
+}
+
+bool aclk_online_for_nodes(void) {
+ return aclk_online() && aclk_query_scope_has(HTTP_ACL_NODES);
+}
+
int aclk_ctx_based = 0;
int aclk_disable_runtime = 0;
-int aclk_stats_enabled;
-int aclk_kill_link = 0;
+
+ACLK_DISCONNECT_ACTION disconnect_req = ACLK_NO_DISCONNECT;
usec_t aclk_session_us = 0;
time_t aclk_session_sec = 0;
@@ -49,13 +64,8 @@ float last_backoff_value = 0;
time_t aclk_block_until = 0;
-#ifdef ENABLE_ACLK
mqtt_wss_client mqttwss_client;
-//netdata_mutex_t aclk_shared_state_mutex = NETDATA_MUTEX_INITIALIZER;
-//#define ACLK_SHARED_STATE_LOCK netdata_mutex_lock(&aclk_shared_state_mutex)
-//#define ACLK_SHARED_STATE_UNLOCK netdata_mutex_unlock(&aclk_shared_state_mutex)
-
struct aclk_shared_state aclk_shared_state = {
.mqtt_shutdown_msg_id = -1,
.mqtt_shutdown_msg_rcvd = 0
@@ -152,19 +162,6 @@ biofailed:
return 1;
}
-static int wait_till_cloud_enabled()
-{
- nd_log(NDLS_DAEMON, NDLP_INFO,
- "Waiting for Cloud to be enabled");
-
- while (!netdata_cloud_enabled) {
- sleep_usec(USEC_PER_SEC * 1);
- if (!service_running(SERVICE_ACLK))
- return 1;
- }
- return 0;
-}
-
/**
* Will block until agent is claimed. Returns only if agent claimed
* or if agent needs to shutdown.
@@ -174,15 +171,13 @@ static int wait_till_cloud_enabled()
*/
static int wait_till_agent_claimed(void)
{
- //TODO prevent malloc and freez
- char *agent_id = get_agent_claimid();
- while (likely(!agent_id)) {
+ ND_UUID uuid = claim_id_get_uuid();
+ while (likely(UUIDiszero(uuid))) {
sleep_usec(USEC_PER_SEC * 1);
if (!service_running(SERVICE_ACLK))
return 1;
- agent_id = get_agent_claimid();
+ uuid = claim_id_get_uuid();
}
- freez(agent_id);
return 0;
}
@@ -204,9 +199,9 @@ static int wait_till_agent_claim_ready()
// The NULL return means the value was never initialised, but this value has been initialized in post_conf_load.
// We trap the impossible NULL here to keep the linter happy without using a fatal() in the code.
- char *cloud_base_url = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", NULL);
+ const char *cloud_base_url = cloud_config_url_get();
if (cloud_base_url == NULL) {
- netdata_log_error("Do not move the cloud base url out of post_conf_load!!");
+ netdata_log_error("Do not move the \"url\" out of post_conf_load!!");
return 1;
}
@@ -214,7 +209,7 @@ static int wait_till_agent_claim_ready()
// TODO make it without malloc/free
memset(&url, 0, sizeof(url_t));
if (url_parse(cloud_base_url, &url)) {
- netdata_log_error("Agent is claimed but the URL in configuration key \"cloud base url\" is invalid, please fix");
+ netdata_log_error("Agent is claimed but the URL in configuration key \"url\" is invalid, please fix");
url_t_destroy(&url);
sleep(5);
continue;
@@ -230,30 +225,6 @@ static int wait_till_agent_claim_ready()
return 1;
}
-void aclk_mqtt_wss_log_cb(mqtt_wss_log_type_t log_type, const char* str)
-{
- switch(log_type) {
- case MQTT_WSS_LOG_ERROR:
- case MQTT_WSS_LOG_FATAL:
- nd_log(NDLS_DAEMON, NDLP_ERR, "%s", str);
- return;
-
- case MQTT_WSS_LOG_WARN:
- nd_log(NDLS_DAEMON, NDLP_WARNING, "%s", str);
- return;
-
- case MQTT_WSS_LOG_INFO:
- nd_log(NDLS_DAEMON, NDLP_INFO, "%s", str);
- return;
-
- case MQTT_WSS_LOG_DEBUG:
- return;
-
- default:
- nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown log type from mqtt_wss");
- }
-}
-
static void msg_callback(const char *topic, const void *msg, size_t msglen, int qos)
{
UNUSED(qos);
@@ -299,9 +270,9 @@ static void puback_callback(uint16_t packet_id)
aclk_tbeb_reset();
}
-#ifdef NETDATA_INTERNAL_CHECKS
- aclk_stats_msg_puback(packet_id);
-#endif
+//#ifdef NETDATA_INTERNAL_CHECKS
+// aclk_stats_msg_puback(packet_id);
+//#endif
if (aclk_shared_state.mqtt_shutdown_msg_id == (int)packet_id) {
nd_log(NDLS_DAEMON, NDLP_DEBUG,
@@ -311,21 +282,9 @@ static void puback_callback(uint16_t packet_id)
}
}
-static int read_query_thread_count()
-{
- int threads = MIN(get_netdata_cpus()/2, 6);
- threads = MAX(threads, 2);
- threads = config_get_number(CONFIG_SECTION_CLOUD, "query thread count", threads);
- if(threads < 1) {
- netdata_log_error("You need at least one query thread. Overriding configured setting of \"%d\"", threads);
- threads = 1;
- config_set_number(CONFIG_SECTION_CLOUD, "query thread count", threads);
- }
- return threads;
-}
-
void aclk_graceful_disconnect(mqtt_wss_client client);
+bool schedule_node_update = false;
/* Keeps connection alive and handles all network communications.
* Returns on error or when netdata is shutting down.
* @param client instance of mqtt_wss_client
@@ -334,7 +293,6 @@ void aclk_graceful_disconnect(mqtt_wss_client client);
*/
static int handle_connection(mqtt_wss_client client)
{
- time_t last_periodic_query_wakeup = now_monotonic_sec();
while (service_running(SERVICE_ACLK)) {
// timeout 1000 to check at least once a second
// for netdata_exit
@@ -343,30 +301,32 @@ static int handle_connection(mqtt_wss_client client)
return 1;
}
- if (disconnect_req || aclk_kill_link) {
- nd_log(NDLS_DAEMON, NDLP_NOTICE,
- "Going to restart connection due to disconnect_req=%s (cloud req), aclk_kill_link=%s (reclaim)",
- disconnect_req ? "true" : "false",
- aclk_kill_link ? "true" : "false");
+ if (disconnect_req != ACLK_NO_DISCONNECT) {
+ const char *reason;
+ switch (disconnect_req) {
+ case ACLK_CLOUD_DISCONNECT:
+ reason = "cloud request";
+ break;
+ case ACLK_PING_TIMEOUT:
+ reason = "ping timeout";
+ schedule_node_update = true;
+ break;
+ case ACLK_RELOAD_CONF:
+ reason = "reclaim";
+ break;
+ default:
+ reason = "unknown";
+ break;
+ }
+
+ nd_log(NDLS_DAEMON, NDLP_NOTICE, "Going to restart connection due to \"%s\"", reason);
- disconnect_req = 0;
- aclk_kill_link = 0;
+ disconnect_req = ACLK_NO_DISCONNECT;
aclk_graceful_disconnect(client);
- aclk_queue_unlock();
aclk_shared_state.mqtt_shutdown_msg_id = -1;
aclk_shared_state.mqtt_shutdown_msg_rcvd = 0;
return 1;
}
-
- // mqtt_wss_service will return faster than in one second
- // if there is enough work to do
- time_t now = now_monotonic_sec();
- if (last_periodic_query_wakeup < now) {
- // wake up at least one Query Thread at least
- // once per second
- last_periodic_query_wakeup = now;
- QUERY_THREAD_WAKEUP;
- }
}
return 0;
}
@@ -386,13 +346,12 @@ static inline void mqtt_connected_actions(mqtt_wss_client client)
else
mqtt_wss_subscribe(client, topic, 1);
- aclk_stats_upd_online(1);
- aclk_connected = 1;
+ aclk_set_connected();
aclk_pubacks_per_conn = 0;
aclk_rcvd_cloud_msgs = 0;
aclk_connection_counter++;
- aclk_topic_cache_iter_t iter = ACLK_TOPIC_CACHE_ITER_T_INITIALIZER;
+ size_t iter = 0;
while ((topic = (char*)aclk_topic_cache_iterate(&iter)) != NULL)
mqtt_wss_set_topic_alias(client, topic);
@@ -404,9 +363,6 @@ void aclk_graceful_disconnect(mqtt_wss_client client)
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Preparing to gracefully shutdown ACLK connection");
- aclk_queue_lock();
- aclk_queue_flush();
-
aclk_shared_state.mqtt_shutdown_msg_id = aclk_send_agent_connection_update(client, 0);
time_t t = now_monotonic_sec();
@@ -425,9 +381,8 @@ void aclk_graceful_disconnect(mqtt_wss_client client)
nd_log(NDLS_DAEMON, NDLP_WARNING, "ACLK link is down");
nd_log(NDLS_ACCESS, NDLP_WARNING, "ACLK DISCONNECTED");
- aclk_stats_upd_online(0);
last_disconnect_time = now_realtime_sec();
- aclk_connected = 0;
+ aclk_set_disconnected();
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Attempting to gracefully shutdown the MQTT/WSS connection");
@@ -602,9 +557,9 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
bool fallback_ipv4 = false;
while (service_running(SERVICE_ACLK)) {
- aclk_cloud_base_url = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", NULL);
+ aclk_cloud_base_url = cloud_config_url_get();
if (aclk_cloud_base_url == NULL) {
- error_report("Do not move the cloud base url out of post_conf_load!!");
+ error_report("Do not move the \"url\" out of post_conf_load!!");
aclk_status = ACLK_STATUS_NO_CLOUD_URL;
return -1;
}
@@ -802,12 +757,7 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
*/
void *aclk_main(void *ptr)
{
- struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
-
- struct aclk_stats_thread *stats_thread = NULL;
-
- struct aclk_query_threads query_threads;
- query_threads.thread_list = NULL;
+ struct netdata_static_thread *static_thread = ptr;
ACLK_PROXY_TYPE proxy_type;
aclk_get_proxy(&proxy_type);
@@ -817,24 +767,12 @@ void *aclk_main(void *ptr)
return NULL;
}
- unsigned int proto_hdl_cnt = aclk_init_rx_msg_handlers();
-
-#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
- nd_log(NDLS_DAEMON, NDLP_INFO,
- "Killing ACLK thread -> cloud functionality has been disabled");
-
- static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
- return NULL;
-#endif
- query_threads.count = read_query_thread_count();
-
- if (wait_till_cloud_enabled())
- goto exit;
+ aclk_init_rx_msg_handlers();
if (wait_till_agent_claim_ready())
goto exit;
- if (!(mqttwss_client = mqtt_wss_new("mqtt_wss", aclk_mqtt_wss_log_cb, msg_callback, puback_callback))) {
+ if (!((mqttwss_client = mqtt_wss_new(msg_callback, puback_callback)))) {
netdata_log_error("Couldn't initialize MQTT_WSS network library");
goto exit;
}
@@ -856,28 +794,22 @@ void *aclk_main(void *ptr)
// that send JSON payloads of 10 MB as single messages
mqtt_wss_set_max_buf_size(mqttwss_client, 25*1024*1024);
- aclk_stats_enabled = config_get_boolean(CONFIG_SECTION_CLOUD, "statistics", global_statistics_enabled);
- if (aclk_stats_enabled) {
- stats_thread = callocz(1, sizeof(struct aclk_stats_thread));
- stats_thread->query_thread_count = query_threads.count;
- stats_thread->client = mqttwss_client;
- aclk_stats_thread_prepare(query_threads.count, proto_hdl_cnt);
- stats_thread->thread = nd_thread_create("ACLK_STATS", NETDATA_THREAD_OPTION_JOINABLE, aclk_stats_main_thread, stats_thread);
- }
-
// Keep reconnecting and talking until our time has come
// and the Grim Reaper (netdata_exit) calls
+ netdata_log_info("Starting ACLK query event loop");
+ aclk_query_init(mqttwss_client);
do {
if (aclk_attempt_to_connect(mqttwss_client))
goto exit_full;
- if (unlikely(!query_threads.thread_list))
- aclk_query_threads_start(&query_threads, mqttwss_client);
+ if (schedule_node_update) {
+ schedule_node_state_update(localhost, 0);
+ schedule_node_update = false;
+ }
if (handle_connection(mqttwss_client)) {
- aclk_stats_upd_online(0);
last_disconnect_time = now_realtime_sec();
- aclk_connected = 0;
+ aclk_set_disconnected();
nd_log(NDLS_ACCESS, NDLP_WARNING, "ACLK DISCONNECTED");
}
} while (service_running(SERVICE_ACLK));
@@ -890,16 +822,6 @@ void *aclk_main(void *ptr)
#endif
exit_full:
-// Tear Down
- QUERY_THREAD_WAKEUP_ALL;
-
- aclk_query_threads_cleanup(&query_threads);
-
- if (aclk_stats_enabled) {
- nd_thread_join(stats_thread->thread);
- aclk_stats_thread_cleanup();
- freez(stats_thread);
- }
free_topic_cache();
mqtt_wss_destroy(mqttwss_client);
exit:
@@ -913,17 +835,16 @@ exit:
void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
{
- nd_uuid_t node_id;
- int ret = 0;
+ ND_UUID node_id;
- if (!aclk_connected)
+ if (!aclk_online())
return;
- if (host->node_id && !uuid_is_null(*host->node_id)) {
- uuid_copy(node_id, *host->node_id);
+ if (!UUIDiszero(host->node_id)) {
+ node_id = host->node_id;
}
else {
- ret = get_node_id(&host->host_uuid, &node_id);
+ int ret = get_node_id(&host->host_id.uuid, &node_id.uuid);
if (ret > 0) {
// this means we were not able to check if node_id already present
netdata_log_error("Unable to check for node_id. Ignoring the host state update.");
@@ -933,21 +854,23 @@ void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
// node_id not found
aclk_query_t create_query;
create_query = aclk_query_new(REGISTER_NODE);
- rrdhost_aclk_state_lock(localhost);
+ CLAIM_ID claim_id = claim_id_get();
+
node_instance_creation_t node_instance_creation = {
- .claim_id = localhost->aclk_state.claimed_id,
+ .claim_id = claim_id_is_set(claim_id) ? claim_id.str : NULL,
.hops = host->system_info->hops,
.hostname = rrdhost_hostname(host),
.machine_guid = host->machine_guid};
+
create_query->data.bin_payload.payload =
generate_node_instance_creation(&create_query->data.bin_payload.size, &node_instance_creation);
- rrdhost_aclk_state_unlock(localhost);
+
create_query->data.bin_payload.topic = ACLK_TOPICID_CREATE_NODE;
create_query->data.bin_payload.msg_name = "CreateNodeInstance";
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Registering host=%s, hops=%u", host->machine_guid, host->system_info->hops);
- aclk_queue_query(create_query);
+ aclk_execute_query(create_query);
return;
}
}
@@ -960,14 +883,13 @@ void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
.session_id = aclk_session_newarch
};
node_state_update.node_id = mallocz(UUID_STR_LEN);
- uuid_unparse_lower(node_id, (char*)node_state_update.node_id);
+ uuid_unparse_lower(node_id.uuid, (char*)node_state_update.node_id);
node_state_update.capabilities = aclk_get_agent_capas();
- rrdhost_aclk_state_lock(localhost);
- node_state_update.claim_id = localhost->aclk_state.claimed_id;
+ CLAIM_ID claim_id = claim_id_get();
+ node_state_update.claim_id = claim_id_is_set(claim_id) ? claim_id.str : NULL;
query->data.bin_payload.payload = generate_node_instance_connection(&query->data.bin_payload.size, &node_state_update);
- rrdhost_aclk_state_unlock(localhost);
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Queuing status update for node=%s, live=%d, hops=%u, queryable=%d",
@@ -975,7 +897,7 @@ void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
freez((void*)node_state_update.node_id);
query->data.bin_payload.msg_name = "UpdateNodeInstanceConnection";
query->data.bin_payload.topic = ACLK_TOPICID_NODE_CONN;
- aclk_queue_query(query);
+ aclk_execute_query(query);
}
void aclk_send_node_instances()
@@ -1009,10 +931,9 @@ void aclk_send_node_instances()
}
node_state_update.capabilities = aclk_get_node_instance_capas(host);
- rrdhost_aclk_state_lock(localhost);
- node_state_update.claim_id = localhost->aclk_state.claimed_id;
+ CLAIM_ID claim_id = claim_id_get();
+ node_state_update.claim_id = claim_id_is_set(claim_id) ? claim_id.str : NULL;
query->data.bin_payload.payload = generate_node_instance_connection(&query->data.bin_payload.size, &node_state_update);
- rrdhost_aclk_state_unlock(localhost);
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Queuing status update for node=%s, live=%d, hops=%d, queryable=1",
@@ -1022,7 +943,7 @@ void aclk_send_node_instances()
freez((void*)node_state_update.node_id);
query->data.bin_payload.msg_name = "UpdateNodeInstanceConnection";
query->data.bin_payload.topic = ACLK_TOPICID_NODE_CONN;
- aclk_queue_query(query);
+ aclk_execute_query(query);
} else {
aclk_query_t create_query;
create_query = aclk_query_new(REGISTER_NODE);
@@ -1034,17 +955,17 @@ void aclk_send_node_instances()
uuid_unparse_lower(list->host_id, (char*)node_instance_creation.machine_guid);
create_query->data.bin_payload.topic = ACLK_TOPICID_CREATE_NODE;
create_query->data.bin_payload.msg_name = "CreateNodeInstance";
- rrdhost_aclk_state_lock(localhost);
- node_instance_creation.claim_id = localhost->aclk_state.claimed_id,
+
+ CLAIM_ID claim_id = claim_id_get();
+ node_instance_creation.claim_id = claim_id_is_set(claim_id) ? claim_id.str : NULL,
create_query->data.bin_payload.payload = generate_node_instance_creation(&create_query->data.bin_payload.size, &node_instance_creation);
- rrdhost_aclk_state_unlock(localhost);
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"Queuing registration for host=%s, hops=%d",
(char*)node_instance_creation.machine_guid, list->hops);
freez((void *)node_instance_creation.machine_guid);
- aclk_queue_query(create_query);
+ aclk_execute_query(create_query);
}
freez(list->hostname);
@@ -1089,38 +1010,37 @@ char *aclk_state(void)
);
buffer_sprintf(wb, "Protocol Used: Protobuf\nMQTT Version: %d\nClaimed: ", 5);
- char *agent_id = get_agent_claimid();
- if (agent_id == NULL)
+ CLAIM_ID claim_id = claim_id_get();
+ if (!claim_id_is_set(claim_id))
buffer_strcat(wb, "No\n");
else {
- char *cloud_base_url = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", NULL);
- buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\n", agent_id, cloud_base_url ? cloud_base_url : "null");
- freez(agent_id);
+ const char *cloud_base_url = cloud_config_url_get();
+ buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null");
}
- buffer_sprintf(wb, "Online: %s\nReconnect count: %d\nBanned By Cloud: %s\n", aclk_connected ? "Yes" : "No", aclk_connection_counter > 0 ? (aclk_connection_counter - 1) : 0, aclk_disable_runtime ? "Yes" : "No");
- if (last_conn_time_mqtt && (tmptr = localtime_r(&last_conn_time_mqtt, &tmbuf)) ) {
+ buffer_sprintf(wb, "Online: %s\nReconnect count: %d\nBanned By Cloud: %s\n", aclk_online() ? "Yes" : "No", aclk_connection_counter > 0 ? (aclk_connection_counter - 1) : 0, aclk_disable_runtime ? "Yes" : "No");
+ if (last_conn_time_mqtt && ((tmptr = localtime_r(&last_conn_time_mqtt, &tmbuf))) ) {
char timebuf[26];
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
buffer_sprintf(wb, "Last Connection Time: %s\n", timebuf);
}
- if (last_conn_time_appl && (tmptr = localtime_r(&last_conn_time_appl, &tmbuf)) ) {
+ if (last_conn_time_appl && ((tmptr = localtime_r(&last_conn_time_appl, &tmbuf))) ) {
char timebuf[26];
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
buffer_sprintf(wb, "Last Connection Time + %d PUBACKs received: %s\n", ACLK_PUBACKS_CONN_STABLE, timebuf);
}
- if (last_disconnect_time && (tmptr = localtime_r(&last_disconnect_time, &tmbuf)) ) {
+ if (last_disconnect_time && ((tmptr = localtime_r(&last_disconnect_time, &tmbuf))) ) {
char timebuf[26];
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
buffer_sprintf(wb, "Last Disconnect Time: %s\n", timebuf);
}
- if (!aclk_connected && next_connection_attempt && (tmptr = localtime_r(&next_connection_attempt, &tmbuf)) ) {
+ if (!aclk_connected && next_connection_attempt && ((tmptr = localtime_r(&next_connection_attempt, &tmbuf))) ) {
char timebuf[26];
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
buffer_sprintf(wb, "Next Connection Attempt At: %s\nLast Backoff: %.3f", timebuf, last_backoff_value);
}
- if (aclk_connected) {
+ if (aclk_online()) {
buffer_sprintf(wb, "Received Cloud MQTT Messages: %d\nMQTT Messages Confirmed by Remote Broker (PUBACKs): %d", aclk_rcvd_cloud_msgs, aclk_pubacks_per_conn);
RRDHOST *host;
@@ -1129,20 +1049,18 @@ char *aclk_state(void)
buffer_sprintf(wb, "\n\n> Node Instance for mGUID: \"%s\" hostname \"%s\"\n", host->machine_guid, rrdhost_hostname(host));
buffer_strcat(wb, "\tClaimed ID: ");
- rrdhost_aclk_state_lock(host);
- if (host->aclk_state.claimed_id)
- buffer_strcat(wb, host->aclk_state.claimed_id);
+ claim_id = rrdhost_claim_id_get(host);
+ if(claim_id_is_set(claim_id))
+ buffer_strcat(wb, claim_id.str);
else
buffer_strcat(wb, "null");
- rrdhost_aclk_state_unlock(host);
-
- if (host->node_id == NULL || uuid_is_null(*host->node_id)) {
+ if (UUIDiszero(host->node_id))
buffer_strcat(wb, "\n\tNode ID: null\n");
- } else {
- char node_id[GUID_LEN + 1];
- uuid_unparse_lower(*host->node_id, node_id);
- buffer_sprintf(wb, "\n\tNode ID: %s\n", node_id);
+ else {
+ char node_id_str[UUID_STR_LEN];
+ uuid_unparse_lower(host->node_id.uuid, node_id_str);
+ buffer_sprintf(wb, "\n\tNode ID: %s\n", node_id_str);
}
buffer_sprintf(wb, "\tStreaming Hops: %d\n\tRelationship: %s", host->system_info->hops, host == localhost ? "self" : "child");
@@ -1183,7 +1101,7 @@ static void fill_alert_status_for_host_json(json_object *obj, RRDHOST *host)
static json_object *timestamp_to_json(const time_t *t)
{
struct tm *tmptr, tmbuf;
- if (*t && (tmptr = gmtime_r(t, &tmbuf)) ) {
+ if (*t && ((tmptr = gmtime_r(t, &tmbuf))) ) {
char timebuf[26];
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
return json_object_new_string(timebuf);
@@ -1206,22 +1124,21 @@ char *aclk_state_json(void)
json_object_array_add(grp, tmp);
json_object_object_add(msg, "protocols-supported", grp);
- char *agent_id = get_agent_claimid();
- tmp = json_object_new_boolean(agent_id != NULL);
+ CLAIM_ID claim_id = claim_id_get();
+ tmp = json_object_new_boolean(claim_id_is_set(claim_id));
json_object_object_add(msg, "agent-claimed", tmp);
- if (agent_id) {
- tmp = json_object_new_string(agent_id);
- freez(agent_id);
- } else
+ if (claim_id_is_set(claim_id))
+ tmp = json_object_new_string(claim_id.str);
+ else
tmp = NULL;
json_object_object_add(msg, "claimed-id", tmp);
- char *cloud_base_url = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", NULL);
+ const char *cloud_base_url = cloud_config_url_get();
tmp = cloud_base_url ? json_object_new_string(cloud_base_url) : NULL;
json_object_object_add(msg, "cloud-url", tmp);
- tmp = json_object_new_boolean(aclk_connected);
+ tmp = json_object_new_boolean(aclk_online());
json_object_object_add(msg, "online", tmp);
tmp = json_object_new_string("Protobuf");
@@ -1242,9 +1159,9 @@ char *aclk_state_json(void)
json_object_object_add(msg, "last-connect-time-utc", timestamp_to_json(&last_conn_time_mqtt));
json_object_object_add(msg, "last-connect-time-puback-utc", timestamp_to_json(&last_conn_time_appl));
json_object_object_add(msg, "last-disconnect-time-utc", timestamp_to_json(&last_disconnect_time));
- json_object_object_add(msg, "next-connection-attempt-utc", !aclk_connected ? timestamp_to_json(&next_connection_attempt) : NULL);
+ json_object_object_add(msg, "next-connection-attempt-utc", !aclk_online() ? timestamp_to_json(&next_connection_attempt) : NULL);
tmp = NULL;
- if (!aclk_connected && last_backoff_value)
+ if (!aclk_online() && last_backoff_value)
tmp = json_object_new_double(last_backoff_value);
json_object_object_add(msg, "last-backoff-value", tmp);
@@ -1264,20 +1181,19 @@ char *aclk_state_json(void)
tmp = json_object_new_string(host->machine_guid);
json_object_object_add(nodeinstance, "mguid", tmp);
- rrdhost_aclk_state_lock(host);
- if (host->aclk_state.claimed_id) {
- tmp = json_object_new_string(host->aclk_state.claimed_id);
+ claim_id = rrdhost_claim_id_get(host);
+ if(claim_id_is_set(claim_id)) {
+ tmp = json_object_new_string(claim_id.str);
json_object_object_add(nodeinstance, "claimed_id", tmp);
} else
json_object_object_add(nodeinstance, "claimed_id", NULL);
- rrdhost_aclk_state_unlock(host);
- if (host->node_id == NULL || uuid_is_null(*host->node_id)) {
+ if (UUIDiszero(host->node_id)) {
json_object_object_add(nodeinstance, "node-id", NULL);
} else {
- char node_id[GUID_LEN + 1];
- uuid_unparse_lower(*host->node_id, node_id);
- tmp = json_object_new_string(node_id);
+ char node_id_str[UUID_STR_LEN];
+ uuid_unparse_lower(host->node_id.uuid, node_id_str);
+ tmp = json_object_new_string(node_id_str);
json_object_object_add(nodeinstance, "node-id", tmp);
}
@@ -1303,12 +1219,10 @@ char *aclk_state_json(void)
json_object_put(msg);
return str;
}
-#endif /* ENABLE_ACLK */
void add_aclk_host_labels(void) {
RRDLABELS *labels = localhost->rrdlabels;
-#ifdef ENABLE_ACLK
rrdlabels_add(labels, "_aclk_available", "true", RRDLABEL_SRC_AUTO|RRDLABEL_SRC_ACLK);
ACLK_PROXY_TYPE aclk_proxy;
char *proxy_str;
@@ -1329,9 +1243,6 @@ void add_aclk_host_labels(void) {
rrdlabels_add(labels, "_mqtt_version", "5", RRDLABEL_SRC_AUTO);
rrdlabels_add(labels, "_aclk_proxy", proxy_str, RRDLABEL_SRC_AUTO);
rrdlabels_add(labels, "_aclk_ng_new_cloud_protocol", "true", RRDLABEL_SRC_AUTO|RRDLABEL_SRC_ACLK);
-#else
- rrdlabels_add(labels, "_aclk_available", "false", RRDLABEL_SRC_AUTO|RRDLABEL_SRC_ACLK);
-#endif
}
void aclk_queue_node_info(RRDHOST *host, bool immediate)
diff --git a/src/aclk/aclk.h b/src/aclk/aclk.h
index 72d1a2e11..45a2eac85 100644
--- a/src/aclk/aclk.h
+++ b/src/aclk/aclk.h
@@ -4,14 +4,19 @@
#include "daemon/common.h"
-#ifdef ENABLE_ACLK
#include "aclk_util.h"
-#include "aclk_rrdhost_state.h"
+//#include "aclk_rrdhost_state.h"
// How many MQTT PUBACKs we need to get to consider connection
// stable for the purposes of TBEB (truncated binary exponential backoff)
#define ACLK_PUBACKS_CONN_STABLE 3
-#endif /* ENABLE_ACLK */
+
+typedef enum {
+ ACLK_NO_DISCONNECT = 0,
+ ACLK_CLOUD_DISCONNECT = 1,
+ ACLK_RELOAD_CONF = 2,
+ ACLK_PING_TIMEOUT = 3
+} ACLK_DISCONNECT_ACTION;
typedef enum __attribute__((packed)) {
ACLK_STATUS_CONNECTED = 0,
@@ -39,12 +44,19 @@ extern ACLK_STATUS aclk_status;
extern const char *aclk_cloud_base_url;
const char *aclk_status_to_string(void);
-extern int aclk_connected;
extern int aclk_ctx_based;
extern int aclk_disable_runtime;
-extern int aclk_stats_enabled;
+//extern int aclk_stats_enabled;
extern int aclk_kill_link;
+bool aclk_online(void);
+bool aclk_online_for_contexts(void);
+bool aclk_online_for_alerts(void);
+bool aclk_online_for_nodes(void);
+
+void aclk_config_get_query_scope(void);
+bool aclk_query_scope_has(HTTP_ACL acl);
+
extern time_t last_conn_time_mqtt;
extern time_t last_conn_time_appl;
extern time_t last_disconnect_time;
@@ -57,15 +69,10 @@ extern time_t aclk_session_sec;
extern time_t aclk_block_until;
extern int aclk_connection_counter;
-extern int disconnect_req;
+extern ACLK_DISCONNECT_ACTION disconnect_req;
-#ifdef ENABLE_ACLK
void *aclk_main(void *ptr);
-extern netdata_mutex_t aclk_shared_state_mutex;
-#define ACLK_SHARED_STATE_LOCK netdata_mutex_lock(&aclk_shared_state_mutex)
-#define ACLK_SHARED_STATE_UNLOCK netdata_mutex_unlock(&aclk_shared_state_mutex)
-
extern struct aclk_shared_state {
// To wait for `disconnect` message PUBACK
// when shutting down
@@ -80,8 +87,6 @@ void aclk_send_node_instances(void);
void aclk_send_bin_msg(char *msg, size_t msg_len, enum aclk_topics subtopic, const char *msgname);
-#endif /* ENABLE_ACLK */
-
char *aclk_state(void);
char *aclk_state_json(void);
void add_aclk_host_labels(void);
diff --git a/src/aclk/aclk_alarm_api.c b/src/aclk/aclk_alarm_api.c
index 664671f70..a23ad0ff7 100644
--- a/src/aclk/aclk_alarm_api.c
+++ b/src/aclk/aclk_alarm_api.c
@@ -8,15 +8,6 @@
#include "aclk.h"
-void aclk_send_provide_alarm_checkpoint(struct alarm_checkpoint *checkpoint)
-{
- aclk_query_t query = aclk_query_new(ALARM_PROVIDE_CHECKPOINT);
- query->data.bin_payload.payload = generate_alarm_checkpoint(&query->data.bin_payload.size, checkpoint);
- query->data.bin_payload.topic = ACLK_TOPICID_ALARM_CHECKPOINT;
- query->data.bin_payload.msg_name = "AlarmCheckpoint";
- QUEUE_IF_PAYLOAD_PRESENT(query);
-}
-
void aclk_send_alarm_log_entry(struct alarm_log_entry *log_entry)
{
size_t payload_size;
diff --git a/src/aclk/aclk_alarm_api.h b/src/aclk/aclk_alarm_api.h
index 4d9d9447a..952d55007 100644
--- a/src/aclk/aclk_alarm_api.h
+++ b/src/aclk/aclk_alarm_api.h
@@ -6,7 +6,6 @@
#include "../daemon/common.h"
#include "schema-wrappers/schema_wrappers.h"
-void aclk_send_provide_alarm_checkpoint(struct alarm_checkpoint *checkpoint);
void aclk_send_alarm_log_entry(struct alarm_log_entry *log_entry);
void aclk_send_provide_alarm_cfg(struct provide_alarm_configuration *cfg);
void aclk_send_alarm_snapshot(alarm_snapshot_proto_ptr_t snapshot);
diff --git a/src/aclk/aclk_capas.c b/src/aclk/aclk_capas.c
index 0f7870fdd..dee6bf0c5 100644
--- a/src/aclk/aclk_capas.c
+++ b/src/aclk/aclk_capas.c
@@ -4,7 +4,11 @@
#include "ml/ml.h"
-#define HTTP_API_V2_VERSION 6
+#define HTTP_API_V2_VERSION 7
+
+size_t aclk_get_http_api_version(void) {
+ return HTTP_API_V2_VERSION;
+}
const struct capability *aclk_get_agent_capas()
{
@@ -24,8 +28,8 @@ const struct capability *aclk_get_agent_capas()
agent_capabilities[2].version = ml_capable() ? 1 : 0;
agent_capabilities[2].enabled = ml_enabled(localhost);
- agent_capabilities[3].version = enable_metric_correlations ? metric_correlations_version : 0;
- agent_capabilities[3].enabled = enable_metric_correlations;
+ agent_capabilities[3].version = metric_correlations_version;
+ agent_capabilities[3].enabled = 1;
agent_capabilities[7].enabled = localhost->health.health_enabled;
@@ -40,9 +44,7 @@ struct capability *aclk_get_node_instance_capas(RRDHOST *host)
struct capability ni_caps[] = {
{ .name = "proto", .version = 1, .enabled = 1 },
{ .name = "ml", .version = ml_capable(), .enabled = ml_enabled(host) },
- { .name = "mc",
- .version = enable_metric_correlations ? metric_correlations_version : 0,
- .enabled = enable_metric_correlations },
+ { .name = "mc", .version = metric_correlations_version, .enabled = 1 },
{ .name = "ctx", .version = 1, .enabled = 1 },
{ .name = "funcs", .version = functions ? 1 : 0, .enabled = functions ? 1 : 0 },
{ .name = "http_api_v2", .version = HTTP_API_V2_VERSION, .enabled = 1 },
diff --git a/src/aclk/aclk_capas.h b/src/aclk/aclk_capas.h
index c39a197b8..d3808e640 100644
--- a/src/aclk/aclk_capas.h
+++ b/src/aclk/aclk_capas.h
@@ -8,6 +8,7 @@
#include "schema-wrappers/capability.h"
+size_t aclk_get_http_api_version(void);
const struct capability *aclk_get_agent_capas();
struct capability *aclk_get_node_instance_capas(RRDHOST *host);
diff --git a/src/aclk/aclk_otp.c b/src/aclk/aclk_otp.c
index 3b8222931..3e4f7835a 100644
--- a/src/aclk/aclk_otp.c
+++ b/src/aclk/aclk_otp.c
@@ -4,10 +4,6 @@
#include "aclk_util.h"
#include "aclk.h"
-#include "daemon/common.h"
-
-#include "mqtt_websockets/c-rbuf/cringbuffer.h"
-
static int aclk_https_request(https_req_t *request, https_req_response_t *response, bool *fallback_ipv4) {
int rc;
// wrapper for ACLK only which loads ACLK specific proxy settings
@@ -271,40 +267,8 @@ exit:
}
#endif
-#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
-static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
-{
- EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
-
- if (ctx != NULL) {
- memset(ctx, 0, sizeof(*ctx));
- }
- return ctx;
-}
-static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
-{
- OPENSSL_free(ctx);
- return;
-}
-#endif
-
#define CHALLENGE_LEN 256
#define CHALLENGE_LEN_BASE64 344
-inline static int base64_decode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
-{
- unsigned char remaining_data[CHALLENGE_LEN];
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- EVP_DecodeInit(ctx);
- EVP_DecodeUpdate(ctx, out, outl, in, in_len);
- int remainder = 0;
- EVP_DecodeFinal(ctx, remaining_data, &remainder);
- EVP_ENCODE_CTX_free(ctx);
- if (remainder) {
- netdata_log_error("Unexpected data at EVP_DecodeFinal");
- return 1;
- }
- return 0;
-}
#define OTP_URL_PREFIX "/api/v1/auth/node/"
int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **challenge, int *challenge_bytes, bool *fallback_ipv4)
@@ -351,7 +315,7 @@ int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **
goto cleanup_json;
}
const char *challenge_base64;
- if (!(challenge_base64 = json_object_get_string(challenge_json))) {
+ if (!((challenge_base64 = json_object_get_string(challenge_json)))) {
netdata_log_error("Failed to extract challenge from JSON object");
goto cleanup_json;
}
@@ -360,8 +324,9 @@ int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **
goto cleanup_json;
}
- *challenge = mallocz((CHALLENGE_LEN_BASE64 / 4) * 3);
- base64_decode_helper(*challenge, challenge_bytes, (const unsigned char*)challenge_base64, strlen(challenge_base64));
+ *challenge = mallocz((CHALLENGE_LEN_BASE64 / 4) * 3 + 1);
+ *challenge_bytes = netdata_base64_decode(*challenge, (const unsigned char *) challenge_base64, CHALLENGE_LEN_BASE64);
+
if (*challenge_bytes != CHALLENGE_LEN) {
netdata_log_error("Unexpected challenge length of %d instead of %d", *challenge_bytes, CHALLENGE_LEN);
freez(*challenge);
@@ -379,7 +344,6 @@ cleanup_resp:
int aclk_send_otp_response(const char *agent_id, const unsigned char *response, int response_bytes, url_t *target, struct auth_data *mqtt_auth, bool *fallback_ipv4)
{
- int len;
int rc = 1;
https_req_t req = HTTPS_REQ_T_INITIALIZER;
https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
@@ -391,7 +355,7 @@ int aclk_send_otp_response(const char *agent_id, const unsigned char *response,
unsigned char base64[CHALLENGE_LEN_BASE64 + 1];
memset(base64, 0, CHALLENGE_LEN_BASE64 + 1);
- base64_encode_helper(base64, &len, response, response_bytes);
+ (void) netdata_base64_encode(base64, response, response_bytes);
BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
BUFFER *resp_json = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
@@ -487,16 +451,15 @@ int aclk_get_mqtt_otp(RSA *p_key, char **mqtt_id, char **mqtt_usr, char **mqtt_p
unsigned char *challenge = NULL;
int challenge_bytes;
- char *agent_id = get_agent_claimid();
- if (agent_id == NULL) {
+ CLAIM_ID claim_id = claim_id_get();
+ if (!claim_id_is_set(claim_id)) {
netdata_log_error("Agent was not claimed - cannot perform challenge/response");
return 1;
}
// Get Challenge
- if (aclk_get_otp_challenge(target, agent_id, &challenge, &challenge_bytes, fallback_ipv4)) {
+ if (aclk_get_otp_challenge(target, claim_id.str, &challenge, &challenge_bytes, fallback_ipv4)) {
netdata_log_error("Error getting challenge");
- freez(agent_id);
return 1;
}
@@ -507,17 +470,15 @@ int aclk_get_mqtt_otp(RSA *p_key, char **mqtt_id, char **mqtt_usr, char **mqtt_p
netdata_log_error("Couldn't decrypt the challenge received");
freez(response_plaintext);
freez(challenge);
- freez(agent_id);
return 1;
}
freez(challenge);
// Encode and Send Challenge
struct auth_data data = { .client_id = NULL, .passwd = NULL, .username = NULL };
- if (aclk_send_otp_response(agent_id, response_plaintext, response_plaintext_bytes, target, &data, fallback_ipv4)) {
+ if (aclk_send_otp_response(claim_id.str, response_plaintext, response_plaintext_bytes, target, &data, fallback_ipv4)) {
netdata_log_error("Error getting response");
freez(response_plaintext);
- freez(agent_id);
return 1;
}
@@ -526,7 +487,6 @@ int aclk_get_mqtt_otp(RSA *p_key, char **mqtt_id, char **mqtt_usr, char **mqtt_p
*mqtt_id = data.client_id;
freez(response_plaintext);
- freez(agent_id);
return 0;
}
@@ -830,17 +790,14 @@ int aclk_get_env(aclk_env_t *env, const char* aclk_hostname, int aclk_port, bool
req.request_type = HTTP_REQ_GET;
- char *agent_id = get_agent_claimid();
- if (agent_id == NULL)
- {
+ CLAIM_ID claim_id = claim_id_get();
+ if (!claim_id_is_set(claim_id)) {
netdata_log_error("Agent was not claimed - cannot perform challenge/response");
buffer_free(buf);
return 1;
}
- buffer_sprintf(buf, "/api/v1/env?v=%s&cap=proto,ctx&claim_id=%s", &(NETDATA_VERSION[1]) /* skip 'v' at beginning */, agent_id);
-
- freez(agent_id);
+ buffer_sprintf(buf, "/api/v1/env?v=%s&cap=proto,ctx&claim_id=%s", &(NETDATA_VERSION[1]) /* skip 'v' at beginning */, claim_id.str);
req.host = (char*)aclk_hostname;
req.port = aclk_port;
diff --git a/src/aclk/aclk_proxy.c b/src/aclk/aclk_proxy.c
index 8d0e2d657..a6185db7c 100644
--- a/src/aclk/aclk_proxy.c
+++ b/src/aclk/aclk_proxy.c
@@ -79,7 +79,7 @@ static inline int check_socks_enviroment(const char **proxy)
{
char *tmp = getenv("socks_proxy");
- if (!tmp)
+ if (!tmp || !*tmp)
return 1;
if (aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
@@ -97,7 +97,7 @@ static inline int check_http_enviroment(const char **proxy)
{
char *tmp = getenv("http_proxy");
- if (!tmp)
+ if (!tmp || !*tmp)
return 1;
if (aclk_verify_proxy(tmp) == PROXY_TYPE_HTTP) {
@@ -113,15 +113,11 @@ static inline int check_http_enviroment(const char **proxy)
const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
{
- const char *proxy = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
-
- // backward compatibility: "proxy" was in "netdata.conf"
- if (config_exists(CONFIG_SECTION_CLOUD, ACLK_PROXY_CONFIG_VAR))
- proxy = config_get(CONFIG_SECTION_CLOUD, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
+ const char *proxy = cloud_config_proxy_get();
*type = PROXY_DISABLED;
- if (strcmp(proxy, "none") == 0)
+ if (!proxy || !*proxy || strcmp(proxy, "none") == 0)
return proxy;
if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
diff --git a/src/aclk/aclk_query.c b/src/aclk/aclk_query.c
index 08bc2acf3..1d93a5e2d 100644
--- a/src/aclk/aclk_query.c
+++ b/src/aclk/aclk_query.c
@@ -1,16 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "aclk_query.h"
-#include "aclk_stats.h"
#include "aclk_tx_msgs.h"
#include "../../web/server/web_client_cache.h"
-#define WEB_HDR_ACCEPT_ENC "Accept-Encoding:"
-
-pthread_cond_t query_cond_wait = PTHREAD_COND_INITIALIZER;
-pthread_mutex_t query_lock_wait = PTHREAD_MUTEX_INITIALIZER;
-#define QUERY_THREAD_LOCK pthread_mutex_lock(&query_lock_wait)
-#define QUERY_THREAD_UNLOCK pthread_mutex_unlock(&query_lock_wait)
+static HTTP_ACL default_aclk_http_acl = HTTP_ACL_ALL_FEATURES;
struct pending_req_list {
const char *msg_id;
@@ -22,7 +16,17 @@ struct pending_req_list {
};
static struct pending_req_list *pending_req_list_head = NULL;
-static pthread_mutex_t pending_req_list_lock = PTHREAD_MUTEX_INITIALIZER;
+static SPINLOCK pending_req_list_lock = NETDATA_SPINLOCK_INITIALIZER;
+
+void aclk_config_get_query_scope(void) {
+ const char *s = config_get(CONFIG_SECTION_CLOUD, "scope", "full");
+ if(strcmp(s, "license manager") == 0)
+ default_aclk_http_acl = HTTP_ACL_ACLK_LICENSE_MANAGER;
+}
+
+bool aclk_query_scope_has(HTTP_ACL acl) {
+ return (default_aclk_http_acl & acl) == acl;
+}
static struct pending_req_list *pending_req_list_add(const char *msg_id)
{
@@ -30,10 +34,10 @@ static struct pending_req_list *pending_req_list_add(const char *msg_id)
new->msg_id = msg_id;
new->hash = simple_hash(msg_id);
- pthread_mutex_lock(&pending_req_list_lock);
+ spinlock_lock(&pending_req_list_lock);
new->next = pending_req_list_head;
pending_req_list_head = new;
- pthread_mutex_unlock(&pending_req_list_lock);
+ spinlock_unlock(&pending_req_list_lock);
return new;
}
@@ -42,7 +46,7 @@ void pending_req_list_rm(const char *msg_id)
uint32_t hash = simple_hash(msg_id);
struct pending_req_list *prev = NULL;
- pthread_mutex_lock(&pending_req_list_lock);
+ spinlock_lock(&pending_req_list_lock);
struct pending_req_list *curr = pending_req_list_head;
while (curr) {
@@ -59,26 +63,26 @@ void pending_req_list_rm(const char *msg_id)
prev = curr;
curr = curr->next;
}
- pthread_mutex_unlock(&pending_req_list_lock);
+ spinlock_unlock(&pending_req_list_lock);
}
int mark_pending_req_cancelled(const char *msg_id)
{
uint32_t hash = simple_hash(msg_id);
- pthread_mutex_lock(&pending_req_list_lock);
+ spinlock_lock(&pending_req_list_lock);
struct pending_req_list *curr = pending_req_list_head;
while (curr) {
if (curr->hash == hash && strcmp(curr->msg_id, msg_id) == 0) {
curr->canceled = 1;
- pthread_mutex_unlock(&pending_req_list_lock);
+ spinlock_unlock(&pending_req_list_lock);
return 0;
}
curr = curr->next;
}
- pthread_mutex_unlock(&pending_req_list_lock);
+ spinlock_unlock(&pending_req_list_lock);
return 1;
}
@@ -88,7 +92,8 @@ static bool aclk_web_client_interrupt_cb(struct web_client *w __maybe_unused, vo
return req->canceled;
}
-static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query) {
+int http_api_v2(mqtt_wss_client client, aclk_query_t query)
+{
ND_LOG_STACK lgs[] = {
ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "aclk"),
ND_LOG_FIELD_END(),
@@ -97,8 +102,6 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
int retval = 0;
BUFFER *local_buffer = NULL;
- size_t size = 0;
- size_t sent = 0;
usec_t dt_ut = 0;
int z_ret;
@@ -106,7 +109,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
struct web_client *w = web_client_get_from_cache();
web_client_set_conn_cloud(w);
- w->port_acl = HTTP_ACL_ACLK | HTTP_ACL_ALL_FEATURES;
+ w->port_acl = HTTP_ACL_ACLK | default_aclk_http_acl;
w->acl = w->port_acl;
web_client_set_permissions(w, HTTP_ACCESS_MAP_OLD_MEMBER, HTTP_USER_ROLE_MEMBER, WEB_CLIENT_FLAG_AUTH_CLOUD);
@@ -124,7 +127,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
nd_log(NDLS_ACCESS, NDLP_ERR, "ACLK received request is not valid, code %d", validation);
retval = 1;
w->response.code = HTTP_RESP_BAD_REQUEST;
- w->response.code = (short)aclk_http_msg_v2(query_thr->client, query->callback_topic, query->msg_id,
+ w->response.code = (short)aclk_http_msg_v2(client, query->callback_topic, query->msg_id,
dt_ut, query->created, w->response.code,
NULL, 0);
goto cleanup;
@@ -137,39 +140,18 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
dt_ut / USEC_PER_MS, query->timeout);
retval = 1;
w->response.code = HTTP_RESP_SERVICE_UNAVAILABLE;
- aclk_http_msg_v2_err(query_thr->client, query->callback_topic, query->msg_id, w->response.code, CLOUD_EC_SND_TIMEOUT, CLOUD_EMSG_SND_TIMEOUT, NULL, 0);
+ aclk_http_msg_v2_err(client, query->callback_topic, query->msg_id, w->response.code, CLOUD_EC_SND_TIMEOUT, CLOUD_EMSG_SND_TIMEOUT, NULL, 0);
goto cleanup;
}
char *path = (char *)buffer_tostring(w->url_path_decoded);
- if (aclk_stats_enabled) {
- char *url_path_endpoint = strrchr(path, '/');
- ACLK_STATS_LOCK;
- int stat_idx = aclk_cloud_req_http_type_to_idx(url_path_endpoint ? url_path_endpoint + 1 : "other");
- aclk_metrics_per_sample.cloud_req_http_by_type[stat_idx]++;
- ACLK_STATS_UNLOCK;
- }
-
w->response.code = (short)web_client_api_request_with_node_selection(localhost, w, path);
web_client_timeout_checkpoint_response_ready(w, &dt_ut);
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.cloud_q_process_total += dt_ut;
- aclk_metrics_per_sample.cloud_q_process_count++;
- if (aclk_metrics_per_sample.cloud_q_process_max < dt_ut)
- aclk_metrics_per_sample.cloud_q_process_max = dt_ut;
- ACLK_STATS_UNLOCK;
- }
-
- size = w->response.data->len;
- sent = size;
-
if (w->response.data->len && w->response.zinitialized) {
w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
w->response.zstream.avail_in = w->response.data->len;
-
do {
w->response.zstream.avail_out = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE;
w->response.zstream.next_out = w->response.zbuffer;
@@ -181,7 +163,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
netdata_log_error("Unknown error during zlib compression.");
retval = 1;
w->response.code = 500;
- aclk_http_msg_v2_err(query_thr->client, query->callback_topic, query->msg_id, w->response.code, CLOUD_EC_ZLIB_ERROR, CLOUD_EMSG_ZLIB_ERROR, NULL, 0);
+ aclk_http_msg_v2_err(client, query->callback_topic, query->msg_id, w->response.code, CLOUD_EC_ZLIB_ERROR, CLOUD_EMSG_ZLIB_ERROR, NULL, 0);
goto cleanup;
}
int bytes_to_cpy = NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE - w->response.zstream.avail_out;
@@ -208,16 +190,20 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
buffer_need_bytes(local_buffer, w->response.data->len);
memcpy(&local_buffer->buffer[local_buffer->len], w->response.data->buffer, w->response.data->len);
local_buffer->len += w->response.data->len;
- sent = sent - size + w->response.data->len;
- } else {
+ } else
buffer_strcat(local_buffer, w->response.data->buffer);
- }
}
// send msg.
- w->response.code = (short)aclk_http_msg_v2(query_thr->client, query->callback_topic, query->msg_id,
- dt_ut, query->created, w->response.code,
- local_buffer->buffer, local_buffer->len);
+ w->response.code = (short)aclk_http_msg_v2(
+ client,
+ query->callback_topic,
+ query->msg_id,
+ dt_ut,
+ query->created,
+ w->response.code,
+ local_buffer->buffer,
+ local_buffer->len);
cleanup:
web_client_log_completed_request(w, false);
@@ -230,144 +216,14 @@ cleanup:
return retval;
}
-static int send_bin_msg(struct aclk_query_thread *query_thr, aclk_query_t query)
+int send_bin_msg(mqtt_wss_client client, aclk_query_t query)
{
// this will be simplified when legacy support is removed
- aclk_send_bin_message_subtopic_pid(query_thr->client, query->data.bin_payload.payload, query->data.bin_payload.size, query->data.bin_payload.topic, query->data.bin_payload.msg_name);
+ aclk_send_bin_message_subtopic_pid(
+ client,
+ query->data.bin_payload.payload,
+ query->data.bin_payload.size,
+ query->data.bin_payload.topic,
+ query->data.bin_payload.msg_name);
return 0;
}
-
-const char *aclk_query_get_name(aclk_query_type_t qt, int unknown_ok)
-{
- switch (qt) {
- case HTTP_API_V2: return "http_api_request_v2";
- case REGISTER_NODE: return "register_node";
- case NODE_STATE_UPDATE: return "node_state_update";
- case CHART_DIMS_UPDATE: return "chart_and_dim_update";
- case CHART_CONFIG_UPDATED: return "chart_config_updated";
- case CHART_RESET: return "reset_chart_messages";
- case RETENTION_UPDATED: return "update_retention_info";
- case UPDATE_NODE_INFO: return "update_node_info";
- case ALARM_PROVIDE_CHECKPOINT: return "alarm_checkpoint";
- case ALARM_PROVIDE_CFG: return "provide_alarm_config";
- case ALARM_SNAPSHOT: return "alarm_snapshot";
- case UPDATE_NODE_COLLECTORS: return "update_node_collectors";
- case PROTO_BIN_MESSAGE: return "generic_binary_proto_message";
- default:
- if (!unknown_ok)
- error_report("Unknown query type used %d", (int) qt);
- return "unknown";
- }
-}
-
-static void aclk_query_process_msg(struct aclk_query_thread *query_thr, aclk_query_t query)
-{
- if (query->type == UNKNOWN || query->type >= ACLK_QUERY_TYPE_COUNT) {
- error_report("Unknown query in query queue. %u", query->type);
- aclk_query_free(query);
- return;
- }
-
- worker_is_busy(query->type);
- if (query->type == HTTP_API_V2) {
- netdata_log_debug(D_ACLK, "Processing Queued Message of type: \"http_api_request_v2\"");
- http_api_v2(query_thr, query);
- } else {
- netdata_log_debug(D_ACLK, "Processing Queued Message of type: \"%s\"", query->data.bin_payload.msg_name);
- send_bin_msg(query_thr, query);
- }
-
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.queries_dispatched++;
- aclk_queries_per_thread[query_thr->idx]++;
- aclk_metrics_per_sample.queries_per_type[query->type]++;
- ACLK_STATS_UNLOCK;
- }
-
- aclk_query_free(query);
-
- worker_is_idle();
-}
-
-/* Processes messages from queue. Compete for work with other threads
- */
-int aclk_query_process_msgs(struct aclk_query_thread *query_thr)
-{
- aclk_query_t query;
- while ((query = aclk_queue_pop()))
- aclk_query_process_msg(query_thr, query);
-
- return 0;
-}
-
-static void worker_aclk_register(void) {
- worker_register("ACLKQUERY");
- for (int i = 1; i < ACLK_QUERY_TYPE_COUNT; i++) {
- worker_register_job_name(i, aclk_query_get_name(i, 0));
- }
-}
-
-static void aclk_query_request_cancel(void *data)
-{
- pthread_cond_broadcast((pthread_cond_t *) data);
-}
-
-/**
- * Main query processing thread
- */
-void *aclk_query_main_thread(void *ptr)
-{
- worker_aclk_register();
-
- struct aclk_query_thread *query_thr = ptr;
-
- service_register(SERVICE_THREAD_TYPE_NETDATA, aclk_query_request_cancel, NULL, &query_cond_wait, false);
-
- while (service_running(SERVICE_ACLK | ABILITY_DATA_QUERIES)) {
- aclk_query_process_msgs(query_thr);
-
- worker_is_idle();
- QUERY_THREAD_LOCK;
- if (unlikely(pthread_cond_wait(&query_cond_wait, &query_lock_wait)))
- sleep_usec(USEC_PER_SEC * 1);
- QUERY_THREAD_UNLOCK;
- }
-
- worker_unregister();
- return NULL;
-}
-
-#define TASK_LEN_MAX 22
-void aclk_query_threads_start(struct aclk_query_threads *query_threads, mqtt_wss_client client)
-{
- netdata_log_info("Starting %d query threads.", query_threads->count);
-
- char thread_name[TASK_LEN_MAX];
- query_threads->thread_list = callocz(query_threads->count, sizeof(struct aclk_query_thread));
- for (int i = 0; i < query_threads->count; i++) {
- query_threads->thread_list[i].idx = i; //thread needs to know its index for statistics
- query_threads->thread_list[i].client = client;
-
- if(unlikely(snprintfz(thread_name, TASK_LEN_MAX, "ACLK_QRY[%d]", i) < 0))
- netdata_log_error("snprintf encoding error");
-
- query_threads->thread_list[i].thread = nd_thread_create(
- thread_name,
- NETDATA_THREAD_OPTION_JOINABLE,
- aclk_query_main_thread,
- &query_threads->thread_list[i]);
- }
-}
-
-void aclk_query_threads_cleanup(struct aclk_query_threads *query_threads)
-{
- if (query_threads && query_threads->thread_list) {
- for (int i = 0; i < query_threads->count; i++) {
- nd_thread_join(query_threads->thread_list[i].thread);
- }
- freez(query_threads->thread_list);
- }
- aclk_queue_lock();
- aclk_queue_flush();
-}
diff --git a/src/aclk/aclk_query.h b/src/aclk/aclk_query.h
index 900583237..04cb460d0 100644
--- a/src/aclk/aclk_query.h
+++ b/src/aclk/aclk_query.h
@@ -9,30 +9,11 @@
#include "aclk_query_queue.h"
-extern pthread_cond_t query_cond_wait;
-extern pthread_mutex_t query_lock_wait;
-#define QUERY_THREAD_WAKEUP pthread_cond_signal(&query_cond_wait)
-#define QUERY_THREAD_WAKEUP_ALL pthread_cond_broadcast(&query_cond_wait)
-
-// TODO
-//extern volatile int aclk_connected;
-
-struct aclk_query_thread {
- ND_THREAD *thread;
- int idx;
- mqtt_wss_client client;
-};
-
-struct aclk_query_threads {
- struct aclk_query_thread *thread_list;
- int count;
-};
-
-void aclk_query_threads_start(struct aclk_query_threads *query_threads, mqtt_wss_client client);
-void aclk_query_threads_cleanup(struct aclk_query_threads *query_threads);
-
-const char *aclk_query_get_name(aclk_query_type_t qt, int unknown_ok);
-
int mark_pending_req_cancelled(const char *msg_id);
+void aclk_execute_query(aclk_query_t query);
+void aclk_query_init(mqtt_wss_client client);
+int http_api_v2(mqtt_wss_client client, aclk_query_t query);
+int send_bin_msg(mqtt_wss_client client, aclk_query_t query);
+
#endif //NETDATA_AGENT_CLOUD_LINK_H
diff --git a/src/aclk/aclk_query_queue.c b/src/aclk/aclk_query_queue.c
index 3edadc002..acaa2d9c6 100644
--- a/src/aclk/aclk_query_queue.c
+++ b/src/aclk/aclk_query_queue.c
@@ -1,87 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "aclk_query_queue.h"
-#include "aclk_query.h"
-#include "aclk_stats.h"
-
-static netdata_mutex_t aclk_query_queue_mutex = NETDATA_MUTEX_INITIALIZER;
-#define ACLK_QUEUE_LOCK netdata_mutex_lock(&aclk_query_queue_mutex)
-#define ACLK_QUEUE_UNLOCK netdata_mutex_unlock(&aclk_query_queue_mutex)
-
-static struct aclk_query_queue {
- aclk_query_t head;
- int block_push;
-} aclk_query_queue = {
- .head = NULL,
- .block_push = 0
-};
-
-static inline int _aclk_queue_query(aclk_query_t query)
-{
- now_monotonic_high_precision_timeval(&query->created_tv);
- query->created = now_realtime_usec();
-
- ACLK_QUEUE_LOCK;
- if (aclk_query_queue.block_push) {
- ACLK_QUEUE_UNLOCK;
- if(service_running(SERVICE_ACLK | ABILITY_DATA_QUERIES))
- netdata_log_error("Query Queue is blocked from accepting new requests. This is normally the case when ACLK prepares to shutdown.");
- aclk_query_free(query);
- return 1;
- }
- DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(aclk_query_queue.head, query, prev, next);
- ACLK_QUEUE_UNLOCK;
- return 0;
-
-}
-
-int aclk_queue_query(aclk_query_t query)
-{
- int ret = _aclk_queue_query(query);
- if (!ret) {
- QUERY_THREAD_WAKEUP;
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.queries_queued++;
- ACLK_STATS_UNLOCK;
- }
- }
- return ret;
-}
-
-aclk_query_t aclk_queue_pop(void)
-{
- aclk_query_t ret;
-
- ACLK_QUEUE_LOCK;
- if (aclk_query_queue.block_push) {
- ACLK_QUEUE_UNLOCK;
- if(service_running(SERVICE_ACLK | ABILITY_DATA_QUERIES))
- netdata_log_error("POP Query Queue is blocked from accepting new requests. This is normally the case when ACLK prepares to shutdown.");
- return NULL;
- }
-
- ret = aclk_query_queue.head;
- if (!ret) {
- ACLK_QUEUE_UNLOCK;
- return ret;
- }
-
- DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(aclk_query_queue.head, ret, prev, next);
- ACLK_QUEUE_UNLOCK;
-
- ret->next = NULL;
- return ret;
-}
-
-void aclk_queue_flush(void)
-{
- aclk_query_t query = aclk_queue_pop();
- while (query) {
- aclk_query_free(query);
- query = aclk_queue_pop();
- }
-}
aclk_query_t aclk_query_new(aclk_query_type_t type)
{
@@ -93,14 +12,14 @@ aclk_query_t aclk_query_new(aclk_query_type_t type)
void aclk_query_free(aclk_query_t query)
{
switch (query->type) {
- case HTTP_API_V2:
- freez(query->data.http_api_v2.payload);
- if (query->data.http_api_v2.query != query->dedup_id)
- freez(query->data.http_api_v2.query);
- break;
-
- default:
- break;
+ case HTTP_API_V2:
+ freez(query->data.http_api_v2.payload);
+ if (query->data.http_api_v2.query != query->dedup_id)
+ freez(query->data.http_api_v2.query);
+ break;
+
+ default:
+ break;
}
freez(query->dedup_id);
@@ -108,17 +27,3 @@ void aclk_query_free(aclk_query_t query)
freez(query->msg_id);
freez(query);
}
-
-void aclk_queue_lock(void)
-{
- ACLK_QUEUE_LOCK;
- aclk_query_queue.block_push = 1;
- ACLK_QUEUE_UNLOCK;
-}
-
-void aclk_queue_unlock(void)
-{
- ACLK_QUEUE_LOCK;
- aclk_query_queue.block_push = 0;
- ACLK_QUEUE_UNLOCK;
-}
diff --git a/src/aclk/aclk_query_queue.h b/src/aclk/aclk_query_queue.h
index 4a4a36a3f..8b7e3a10c 100644
--- a/src/aclk/aclk_query_queue.h
+++ b/src/aclk/aclk_query_queue.h
@@ -14,12 +14,7 @@ typedef enum {
HTTP_API_V2,
REGISTER_NODE,
NODE_STATE_UPDATE,
- CHART_DIMS_UPDATE,
- CHART_CONFIG_UPDATED,
- CHART_RESET,
- RETENTION_UPDATED,
UPDATE_NODE_INFO,
- ALARM_PROVIDE_CHECKPOINT,
ALARM_PROVIDE_CFG,
ALARM_SNAPSHOT,
UPDATE_NODE_COLLECTORS,
@@ -32,7 +27,7 @@ struct aclk_query_http_api_v2 {
char *query;
};
-struct aclk_bin_payload {
+struct aclk_bin_payload {
char *payload;
size_t size;
enum aclk_topics topic;
@@ -55,7 +50,6 @@ struct aclk_query {
struct timeval created_tv;
usec_t created;
int timeout;
- aclk_query_t prev, next;
// TODO maybe remove?
int version;
@@ -68,20 +62,16 @@ struct aclk_query {
aclk_query_t aclk_query_new(aclk_query_type_t type);
void aclk_query_free(aclk_query_t query);
-int aclk_queue_query(aclk_query_t query);
-aclk_query_t aclk_queue_pop(void);
-void aclk_queue_flush(void);
+void aclk_execute_query(aclk_query_t query);
-void aclk_queue_lock(void);
-void aclk_queue_unlock(void);
-
-#define QUEUE_IF_PAYLOAD_PRESENT(query) do { \
- if (likely(query->data.bin_payload.payload)) { \
- aclk_queue_query(query); \
- } else { \
- nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to generate payload"); \
- aclk_query_free(query); \
- } \
-} while(0)
+#define QUEUE_IF_PAYLOAD_PRESENT(query) \
+ do { \
+ if (likely((query)->data.bin_payload.payload)) { \
+ aclk_execute_query(query); \
+ } else { \
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to generate payload"); \
+ aclk_query_free(query); \
+ } \
+ } while (0)
#endif /* NETDATA_ACLK_QUERY_QUEUE_H */
diff --git a/src/aclk/aclk_rrdhost_state.h b/src/aclk/aclk_rrdhost_state.h
deleted file mode 100644
index 5c8a2ddc9..000000000
--- a/src/aclk/aclk_rrdhost_state.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef ACLK_RRDHOST_STATE_H
-#define ACLK_RRDHOST_STATE_H
-
-#include "libnetdata/libnetdata.h"
-
-typedef struct aclk_rrdhost_state {
- char *claimed_id; // Claimed ID if host has one otherwise NULL
- char *prev_claimed_id; // Claimed ID if changed (reclaimed) during runtime
-} aclk_rrdhost_state;
-
-#endif /* ACLK_RRDHOST_STATE_H */
diff --git a/src/aclk/aclk_rx_msgs.c b/src/aclk/aclk_rx_msgs.c
index 8db8e3f1e..36bd3599d 100644
--- a/src/aclk/aclk_rx_msgs.c
+++ b/src/aclk/aclk_rx_msgs.c
@@ -2,7 +2,6 @@
#include "aclk_rx_msgs.h"
-#include "aclk_stats.h"
#include "aclk_query_queue.h"
#include "aclk.h"
#include "aclk_capas.h"
@@ -165,7 +164,7 @@ static int aclk_handle_cloud_http_request_v2(struct aclk_request *cloud_to_agent
// it would be strange to get URL from `dedup_id`
query->data.http_api_v2.query = query->dedup_id;
query->msg_id = cloud_to_agent->msg_id;
- aclk_queue_query(query);
+ aclk_execute_query(query);
return 0;
error:
@@ -268,7 +267,7 @@ int create_node_instance_result(const char *msg, size_t msg_len)
freez(res.node_id);
return 1;
}
- update_node_id(&host_id, &node_id);
+ sql_update_node_id(&host_id, &node_id);
aclk_query_t query = aclk_query_new(NODE_STATE_UPDATE);
node_instance_connection_t node_state_update = {
@@ -292,17 +291,16 @@ int create_node_instance_result(const char *msg, size_t msg_len)
node_state_update.capabilities = aclk_get_node_instance_capas(host);
}
- rrdhost_aclk_state_lock(localhost);
- node_state_update.claim_id = localhost->aclk_state.claimed_id;
+ CLAIM_ID claim_id = claim_id_get();
+ node_state_update.claim_id = claim_id_is_set(claim_id) ? claim_id.str : NULL;
query->data.bin_payload.payload = generate_node_instance_connection(&query->data.bin_payload.size, &node_state_update);
- rrdhost_aclk_state_unlock(localhost);
freez((void *)node_state_update.capabilities);
query->data.bin_payload.msg_name = "UpdateNodeInstanceConnection";
query->data.bin_payload.topic = ACLK_TOPICID_NODE_CONN;
- aclk_queue_query(query);
+ aclk_execute_query(query);
freez(res.node_id);
freez(res.machine_guid);
return 0;
@@ -409,7 +407,7 @@ int handle_disconnect_req(const char *msg, size_t msg_len)
"Cloud asks not to reconnect for %u seconds. We shall honor that request",
(unsigned int)cmd->reconnect_after_s);
}
- disconnect_req = 1;
+ disconnect_req = ACLK_CLOUD_DISCONNECT;
freez(cmd->error_description);
freez(cmd);
return 0;
@@ -503,12 +501,7 @@ new_cloud_rx_msg_t *find_rx_handler_by_hash(simple_hash_t hash)
return NULL;
}
-const char *rx_handler_get_name(size_t i)
-{
- return rx_msgs[i].name;
-}
-
-unsigned int aclk_init_rx_msg_handlers(void)
+void aclk_init_rx_msg_handlers(void)
{
int i;
for (i = 0; rx_msgs[i].fnc; i++) {
@@ -521,29 +514,17 @@ unsigned int aclk_init_rx_msg_handlers(void)
}
rx_msgs[i].name_hash = hash;
}
- return i;
}
void aclk_handle_new_cloud_msg(const char *message_type, const char *msg, size_t msg_len, const char *topic __maybe_unused)
{
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.cloud_req_recvd++;
- ACLK_STATS_UNLOCK;
- }
new_cloud_rx_msg_t *msg_descriptor = find_rx_handler_by_hash(simple_hash(message_type));
netdata_log_debug(D_ACLK, "Got message named '%s' from cloud", message_type);
if (unlikely(!msg_descriptor)) {
netdata_log_error("Do not know how to handle message of type '%s'. Ignoring", message_type);
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.cloud_req_err++;
- ACLK_STATS_UNLOCK;
- }
return;
}
-
if (aclklog_enabled) {
if (!strncmp(message_type, "cmd", strlen("cmd"))) {
log_aclk_message_bin(msg, msg_len, 0, topic, msg_descriptor->name);
@@ -554,18 +535,8 @@ void aclk_handle_new_cloud_msg(const char *message_type, const char *msg, size_t
}
}
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_proto_rx_msgs_sample[msg_descriptor-rx_msgs]++;
- ACLK_STATS_UNLOCK;
- }
if (msg_descriptor->fnc(msg, msg_len)) {
netdata_log_error("Error processing message of type '%s'", message_type);
- if (aclk_stats_enabled) {
- ACLK_STATS_LOCK;
- aclk_metrics_per_sample.cloud_req_err++;
- ACLK_STATS_UNLOCK;
- }
return;
}
}
diff --git a/src/aclk/aclk_rx_msgs.h b/src/aclk/aclk_rx_msgs.h
index 61921faec..ae5dc18b8 100644
--- a/src/aclk/aclk_rx_msgs.h
+++ b/src/aclk/aclk_rx_msgs.h
@@ -1,17 +1,12 @@
-
-
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ACLK_RX_MSGS_H
#define ACLK_RX_MSGS_H
-#include "daemon/common.h"
#include "libnetdata/libnetdata.h"
int aclk_handle_cloud_cmd_message(char *payload);
-
-const char *rx_handler_get_name(size_t i);
-unsigned int aclk_init_rx_msg_handlers(void);
+void aclk_init_rx_msg_handlers(void);
void aclk_handle_new_cloud_msg(const char *message_type, const char *msg, size_t msg_len, const char *topic);
#endif /* ACLK_RX_MSGS_H */
diff --git a/src/aclk/aclk_stats.c b/src/aclk/aclk_stats.c
deleted file mode 100644
index 47a48c366..000000000
--- a/src/aclk/aclk_stats.c
+++ /dev/null
@@ -1,483 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#ifndef MQTT_WSS_CPUSTATS
-#define MQTT_WSS_CPUSTATS
-#endif
-
-#include "aclk_stats.h"
-
-#include "aclk_query.h"
-
-netdata_mutex_t aclk_stats_mutex = NETDATA_MUTEX_INITIALIZER;
-
-struct {
- int query_thread_count;
- unsigned int proto_hdl_cnt;
- uint32_t *aclk_proto_rx_msgs_sample;
- RRDDIM **rx_msg_dims;
-} aclk_stats_cfg; // there is only 1 stats thread at a time
-
-// data ACLK stats need per query thread
-struct aclk_qt_data {
- RRDDIM *dim;
-} *aclk_qt_data = NULL;
-
-uint32_t *aclk_queries_per_thread = NULL;
-uint32_t *aclk_queries_per_thread_sample = NULL;
-uint32_t *aclk_proto_rx_msgs_sample = NULL;
-
-struct aclk_metrics aclk_metrics = {
- .online = 0,
-};
-
-struct aclk_metrics_per_sample aclk_metrics_per_sample;
-
-static void aclk_stats_collect(struct aclk_metrics_per_sample *per_sample, struct aclk_metrics *permanent)
-{
- static RRDSET *st_aclkstats = NULL;
- static RRDDIM *rd_online_status = NULL;
-
- if (unlikely(!st_aclkstats)) {
- st_aclkstats = rrdset_create_localhost(
- "netdata", "aclk_status", NULL, "aclk", NULL, "ACLK/Cloud connection status",
- "connected", "netdata", "stats", 200000, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-
- rd_online_status = rrddim_add(st_aclkstats, "online", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- }
-
- rrddim_set_by_pointer(st_aclkstats, rd_online_status, per_sample->offline_during_sample ? 0 : permanent->online);
-
- rrdset_done(st_aclkstats);
-}
-
-static void aclk_stats_query_queue(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st_query_thread = NULL;
- static RRDDIM *rd_queued = NULL;
- static RRDDIM *rd_dispatched = NULL;
-
- if (unlikely(!st_query_thread)) {
- st_query_thread = rrdset_create_localhost(
- "netdata", "aclk_query_per_second", NULL, "aclk", NULL, "ACLK Queries per second", "queries/s",
- "netdata", "stats", 200001, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-
- rd_queued = rrddim_add(st_query_thread, "added", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- rd_dispatched = rrddim_add(st_query_thread, "dispatched", NULL, -1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
-
- rrddim_set_by_pointer(st_query_thread, rd_queued, per_sample->queries_queued);
- rrddim_set_by_pointer(st_query_thread, rd_dispatched, per_sample->queries_dispatched);
-
- rrdset_done(st_query_thread);
-}
-
-#ifdef NETDATA_INTERNAL_CHECKS
-static void aclk_stats_latency(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st = NULL;
- static RRDDIM *rd_avg = NULL;
- static RRDDIM *rd_max = NULL;
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_latency_mqtt", NULL, "aclk", NULL, "ACLK Message Publish Latency", "ms",
- "netdata", "stats", 200002, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-
- rd_avg = rrddim_add(st, "avg", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_max = rrddim_add(st, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- }
-
- if(per_sample->latency_count)
- rrddim_set_by_pointer(st, rd_avg, roundf((float)per_sample->latency_total / per_sample->latency_count));
- else
- rrddim_set_by_pointer(st, rd_avg, 0);
-
- rrddim_set_by_pointer(st, rd_max, per_sample->latency_max);
-
- rrdset_done(st);
-}
-#endif
-
-static void aclk_stats_cloud_req(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st = NULL;
- static RRDDIM *rd_rq_rcvd = NULL;
- static RRDDIM *rd_rq_err = NULL;
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_cloud_req", NULL, "aclk", NULL, "Requests received from cloud", "req/s",
- "netdata", "stats", 200005, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- rd_rq_rcvd = rrddim_add(st, "received", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- rd_rq_err = rrddim_add(st, "malformed", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
-
- rrddim_set_by_pointer(st, rd_rq_rcvd, per_sample->cloud_req_recvd - per_sample->cloud_req_err);
- rrddim_set_by_pointer(st, rd_rq_err, per_sample->cloud_req_err);
-
- rrdset_done(st);
-}
-
-static void aclk_stats_cloud_req_type(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st = NULL;
- static RRDDIM *dims[ACLK_QUERY_TYPE_COUNT];
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_processed_query_type", NULL, "aclk", NULL, "Query thread commands processed by their type", "cmd/s",
- "netdata", "stats", 200006, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- for (int i = 0; i < ACLK_QUERY_TYPE_COUNT; i++)
- dims[i] = rrddim_add(st, aclk_query_get_name(i, 1), NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
-
- }
-
- for (int i = 0; i < ACLK_QUERY_TYPE_COUNT; i++)
- rrddim_set_by_pointer(st, dims[i], per_sample->queries_per_type[i]);
-
- rrdset_done(st);
-}
-
-static char *cloud_req_http_type_names[ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT] = {
- "other",
- "info",
- "data",
- "alarms",
- "alarm_log",
- "chart",
- "charts",
- "function",
- "functions"
- // if you change then update `ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT`.
-};
-
-int aclk_cloud_req_http_type_to_idx(const char *name)
-{
- for (int i = 1; i < ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT; i++)
- if (!strcmp(cloud_req_http_type_names[i], name))
- return i;
- return 0;
-}
-
-static void aclk_stats_cloud_req_http_type(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st = NULL;
- static RRDDIM *rd_rq_types[ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT];
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_cloud_req_http_type", NULL, "aclk", NULL, "Requests received from cloud via HTTP by their type", "req/s",
- "netdata", "stats", 200007, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- for (int i = 0; i < ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT; i++)
- rd_rq_types[i] = rrddim_add(st, cloud_req_http_type_names[i], NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
-
- for (int i = 0; i < ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT; i++)
- rrddim_set_by_pointer(st, rd_rq_types[i], per_sample->cloud_req_http_by_type[i]);
-
- rrdset_done(st);
-}
-
-#define MAX_DIM_NAME 22
-static void aclk_stats_query_threads(uint32_t *queries_per_thread)
-{
- static RRDSET *st = NULL;
-
- char dim_name[MAX_DIM_NAME];
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_query_threads", NULL, "aclk", NULL, "Queries Processed Per Thread", "req/s",
- "netdata", "stats", 200009, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- for (int i = 0; i < aclk_stats_cfg.query_thread_count; i++) {
- if (snprintfz(dim_name, MAX_DIM_NAME, "Query %d", i) < 0)
- netdata_log_error("snprintf encoding error");
- aclk_qt_data[i].dim = rrddim_add(st, dim_name, NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
- }
-
- for (int i = 0; i < aclk_stats_cfg.query_thread_count; i++) {
- rrddim_set_by_pointer(st, aclk_qt_data[i].dim, queries_per_thread[i]);
- }
-
- rrdset_done(st);
-}
-
-static void aclk_stats_query_time(struct aclk_metrics_per_sample *per_sample)
-{
- static RRDSET *st = NULL;
- static RRDDIM *rd_rq_avg = NULL;
- static RRDDIM *rd_rq_max = NULL;
- static RRDDIM *rd_rq_total = NULL;
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_query_time", NULL, "aclk", NULL, "Time it took to process cloud requested DB queries", "us",
- "netdata", "stats", 200008, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-
- rd_rq_avg = rrddim_add(st, "avg", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- rd_rq_max = rrddim_add(st, "max", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- rd_rq_total = rrddim_add(st, "total", NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
-
- if(per_sample->cloud_q_process_count)
- rrddim_set_by_pointer(st, rd_rq_avg, roundf((float)per_sample->cloud_q_process_total / per_sample->cloud_q_process_count));
- else
- rrddim_set_by_pointer(st, rd_rq_avg, 0);
- rrddim_set_by_pointer(st, rd_rq_max, per_sample->cloud_q_process_max);
- rrddim_set_by_pointer(st, rd_rq_total, per_sample->cloud_q_process_total);
-
- rrdset_done(st);
-}
-
-const char *rx_handler_get_name(size_t i);
-static void aclk_stats_newproto_rx(uint32_t *rx_msgs_sample)
-{
- static RRDSET *st = NULL;
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_protobuf_rx_types", NULL, "aclk", NULL, "Received new cloud architecture messages by their type.", "msg/s",
- "netdata", "stats", 200010, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- for (unsigned int i = 0; i < aclk_stats_cfg.proto_hdl_cnt; i++) {
- aclk_stats_cfg.rx_msg_dims[i] = rrddim_add(st, rx_handler_get_name(i), NULL, 1, localhost->rrd_update_every, RRD_ALGORITHM_ABSOLUTE);
- }
- }
-
- for (unsigned int i = 0; i < aclk_stats_cfg.proto_hdl_cnt; i++)
- rrddim_set_by_pointer(st, aclk_stats_cfg.rx_msg_dims[i], rx_msgs_sample[i]);
-
- rrdset_done(st);
-}
-
-static void aclk_stats_mqtt_wss(struct mqtt_wss_stats *stats)
-{
- static RRDSET *st = NULL;
- static RRDDIM *rd_sent = NULL;
- static RRDDIM *rd_recvd = NULL;
- static uint64_t sent = 0;
- static uint64_t recvd = 0;
-
- static RRDSET *st_txbuf_perc = NULL;
- static RRDDIM *rd_txbuf_perc = NULL;
-
- static RRDSET *st_txbuf = NULL;
- static RRDDIM *rd_tx_buffer_usable = NULL;
- static RRDDIM *rd_tx_buffer_reclaimable = NULL;
- static RRDDIM *rd_tx_buffer_used = NULL;
- static RRDDIM *rd_tx_buffer_free = NULL;
- static RRDDIM *rd_tx_buffer_size = NULL;
-
- static RRDSET *st_timing = NULL;
- static RRDDIM *rd_keepalive = NULL;
- static RRDDIM *rd_read_socket = NULL;
- static RRDDIM *rd_write_socket = NULL;
- static RRDDIM *rd_process_websocket = NULL;
- static RRDDIM *rd_process_mqtt = NULL;
-
- sent += stats->bytes_tx;
- recvd += stats->bytes_rx;
-
- if (unlikely(!st)) {
- st = rrdset_create_localhost(
- "netdata", "aclk_openssl_bytes", NULL, "aclk", NULL, "Received and Sent bytes.", "B/s",
- "netdata", "stats", 200011, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
- rd_recvd = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
- }
-
- if (unlikely(!st_txbuf_perc)) {
- st_txbuf_perc = rrdset_create_localhost(
- "netdata", "aclk_mqtt_tx_perc", NULL, "aclk", NULL, "Actively used percentage of MQTT Tx Buffer,", "%",
- "netdata", "stats", 200012, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-
- rd_txbuf_perc = rrddim_add(st_txbuf_perc, "used", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
- }
-
- if (unlikely(!st_txbuf)) {
- st_txbuf = rrdset_create_localhost(
- "netdata", "aclk_mqtt_tx_queue", NULL, "aclk", NULL, "State of transmit MQTT queue.", "B",
- "netdata", "stats", 200013, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-
- rd_tx_buffer_usable = rrddim_add(st_txbuf, "usable", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_tx_buffer_reclaimable = rrddim_add(st_txbuf, "reclaimable", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_tx_buffer_used = rrddim_add(st_txbuf, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_tx_buffer_free = rrddim_add(st_txbuf, "free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_tx_buffer_size = rrddim_add(st_txbuf, "size", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- }
-
- if (unlikely(!st_timing)) {
- st_timing = rrdset_create_localhost(
- "netdata", "aclk_mqtt_wss_time", NULL, "aclk", NULL, "Time spent handling MQTT, WSS, SSL and network communication.", "us",
- "netdata", "stats", 200014, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
-
- rd_keepalive = rrddim_add(st_timing, "keep-alive", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_read_socket = rrddim_add(st_timing, "socket_read_ssl", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_write_socket = rrddim_add(st_timing, "socket_write_ssl", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_process_websocket = rrddim_add(st_timing, "process_websocket", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- rd_process_mqtt = rrddim_add(st_timing, "process_mqtt", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
- }
-
- rrddim_set_by_pointer(st, rd_sent, sent);
- rrddim_set_by_pointer(st, rd_recvd, recvd);
-
- float usage = ((float)stats->mqtt.tx_buffer_free + stats->mqtt.tx_buffer_reclaimable) / stats->mqtt.tx_buffer_size;
- usage = (1 - usage) * 10000;
- rrddim_set_by_pointer(st_txbuf_perc, rd_txbuf_perc, usage);
-
- rrddim_set_by_pointer(st_txbuf, rd_tx_buffer_usable, stats->mqtt.tx_buffer_reclaimable + stats->mqtt.tx_buffer_free);
- rrddim_set_by_pointer(st_txbuf, rd_tx_buffer_reclaimable, stats->mqtt.tx_buffer_reclaimable);
- rrddim_set_by_pointer(st_txbuf, rd_tx_buffer_used, stats->mqtt.tx_buffer_used);
- rrddim_set_by_pointer(st_txbuf, rd_tx_buffer_free, stats->mqtt.tx_buffer_free);
- rrddim_set_by_pointer(st_txbuf, rd_tx_buffer_size, stats->mqtt.tx_buffer_size);
-
- rrddim_set_by_pointer(st_timing, rd_keepalive, stats->time_keepalive);
- rrddim_set_by_pointer(st_timing, rd_read_socket, stats->time_read_socket);
- rrddim_set_by_pointer(st_timing, rd_write_socket, stats->time_write_socket);
- rrddim_set_by_pointer(st_timing, rd_process_websocket, stats->time_process_websocket);
- rrddim_set_by_pointer(st_timing, rd_process_mqtt, stats->time_process_mqtt);
-
- rrdset_done(st);
- rrdset_done(st_txbuf_perc);
- rrdset_done(st_txbuf);
- rrdset_done(st_timing);
-}
-
-void aclk_stats_thread_prepare(int query_thread_count, unsigned int proto_hdl_cnt)
-{
- aclk_qt_data = callocz(query_thread_count, sizeof(struct aclk_qt_data));
- aclk_queries_per_thread = callocz(query_thread_count, sizeof(uint32_t));
- aclk_queries_per_thread_sample = callocz(query_thread_count, sizeof(uint32_t));
-
- memset(&aclk_metrics_per_sample, 0, sizeof(struct aclk_metrics_per_sample));
-
- aclk_stats_cfg.proto_hdl_cnt = proto_hdl_cnt;
- aclk_stats_cfg.aclk_proto_rx_msgs_sample = callocz(proto_hdl_cnt, sizeof(*aclk_proto_rx_msgs_sample));
- aclk_proto_rx_msgs_sample = callocz(proto_hdl_cnt, sizeof(*aclk_proto_rx_msgs_sample));
- aclk_stats_cfg.rx_msg_dims = callocz(proto_hdl_cnt, sizeof(RRDDIM*));
-}
-
-void aclk_stats_thread_cleanup()
-{
- freez(aclk_stats_cfg.rx_msg_dims);
- freez(aclk_proto_rx_msgs_sample);
- freez(aclk_stats_cfg.aclk_proto_rx_msgs_sample);
- freez(aclk_qt_data);
- freez(aclk_queries_per_thread);
- freez(aclk_queries_per_thread_sample);
-}
-
-void *aclk_stats_main_thread(void *ptr)
-{
- struct aclk_stats_thread *args = ptr;
-
- aclk_stats_cfg.query_thread_count = args->query_thread_count;
-
- heartbeat_t hb;
- heartbeat_init(&hb);
- usec_t step_ut = localhost->rrd_update_every * USEC_PER_SEC;
-
- struct aclk_metrics_per_sample per_sample;
- struct aclk_metrics permanent;
-
- while (service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) {
-
- // ------------------------------------------------------------------------
- // Wait for the next iteration point.
-
- heartbeat_next(&hb, step_ut);
-
- if (!service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) break;
-
- ACLK_STATS_LOCK;
- // to not hold lock longer than necessary, especially not to hold it
- // during database rrd* operations
- memcpy(&per_sample, &aclk_metrics_per_sample, sizeof(struct aclk_metrics_per_sample));
-
- memcpy(aclk_stats_cfg.aclk_proto_rx_msgs_sample, aclk_proto_rx_msgs_sample, sizeof(*aclk_proto_rx_msgs_sample) * aclk_stats_cfg.proto_hdl_cnt);
- memset(aclk_proto_rx_msgs_sample, 0, sizeof(*aclk_proto_rx_msgs_sample) * aclk_stats_cfg.proto_hdl_cnt);
-
- memcpy(&permanent, &aclk_metrics, sizeof(struct aclk_metrics));
- memset(&aclk_metrics_per_sample, 0, sizeof(struct aclk_metrics_per_sample));
-
- memcpy(aclk_queries_per_thread_sample, aclk_queries_per_thread, sizeof(uint32_t) * aclk_stats_cfg.query_thread_count);
- memset(aclk_queries_per_thread, 0, sizeof(uint32_t) * aclk_stats_cfg.query_thread_count);
- ACLK_STATS_UNLOCK;
-
- aclk_stats_collect(&per_sample, &permanent);
- aclk_stats_query_queue(&per_sample);
-#ifdef NETDATA_INTERNAL_CHECKS
- aclk_stats_latency(&per_sample);
-#endif
-
- aclk_stats_cloud_req(&per_sample);
- aclk_stats_cloud_req_type(&per_sample);
- aclk_stats_cloud_req_http_type(&per_sample);
-
- aclk_stats_query_threads(aclk_queries_per_thread_sample);
-
- aclk_stats_query_time(&per_sample);
-
- struct mqtt_wss_stats mqtt_wss_stats = mqtt_wss_get_stats(args->client);
- aclk_stats_mqtt_wss(&mqtt_wss_stats);
-
- aclk_stats_newproto_rx(aclk_stats_cfg.aclk_proto_rx_msgs_sample);
- }
-
- return 0;
-}
-
-void aclk_stats_upd_online(int online) {
- if(!aclk_stats_enabled)
- return;
-
- ACLK_STATS_LOCK;
- aclk_metrics.online = online;
-
- if(!online)
- aclk_metrics_per_sample.offline_during_sample = 1;
- ACLK_STATS_UNLOCK;
-}
-
-#ifdef NETDATA_INTERNAL_CHECKS
-static usec_t pub_time[UINT16_MAX + 1] = {0};
-void aclk_stats_msg_published(uint16_t id)
-{
- ACLK_STATS_LOCK;
- pub_time[id] = now_boottime_usec();
- ACLK_STATS_UNLOCK;
-}
-
-void aclk_stats_msg_puback(uint16_t id)
-{
- ACLK_STATS_LOCK;
- usec_t t;
-
- if (!aclk_stats_enabled) {
- ACLK_STATS_UNLOCK;
- return;
- }
-
- if (unlikely(!pub_time[id])) {
- ACLK_STATS_UNLOCK;
- netdata_log_error("Received PUBACK for unknown message?!");
- return;
- }
-
- t = now_boottime_usec() - pub_time[id];
- t /= USEC_PER_MS;
- pub_time[id] = 0;
- if (aclk_metrics_per_sample.latency_max < t)
- aclk_metrics_per_sample.latency_max = t;
-
- aclk_metrics_per_sample.latency_total += t;
- aclk_metrics_per_sample.latency_count++;
- ACLK_STATS_UNLOCK;
-}
-#endif /* NETDATA_INTERNAL_CHECKS */
diff --git a/src/aclk/aclk_stats.h b/src/aclk/aclk_stats.h
deleted file mode 100644
index e13269557..000000000
--- a/src/aclk/aclk_stats.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#ifndef NETDATA_ACLK_STATS_H
-#define NETDATA_ACLK_STATS_H
-
-#include "daemon/common.h"
-#include "libnetdata/libnetdata.h"
-#include "aclk_query_queue.h"
-#include "mqtt_websockets/mqtt_wss_client.h"
-
-extern netdata_mutex_t aclk_stats_mutex;
-
-#define ACLK_STATS_LOCK netdata_mutex_lock(&aclk_stats_mutex)
-#define ACLK_STATS_UNLOCK netdata_mutex_unlock(&aclk_stats_mutex)
-
-// if you change update `cloud_req_http_type_names`.
-#define ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT 9
-
-int aclk_cloud_req_http_type_to_idx(const char *name);
-
-struct aclk_stats_thread {
- ND_THREAD *thread;
- int query_thread_count;
- mqtt_wss_client client;
-};
-
-// preserve between samples
-struct aclk_metrics {
- volatile uint8_t online;
-};
-
-// reset to 0 on every sample
-extern struct aclk_metrics_per_sample {
- /* in the unlikely event of ACLK disconnecting
- and reconnecting under 1 sampling rate
- we want to make sure we record the disconnection
- despite it being then seemingly longer in graph */
- volatile uint8_t offline_during_sample;
-
- volatile uint32_t queries_queued;
- volatile uint32_t queries_dispatched;
-
-#ifdef NETDATA_INTERNAL_CHECKS
- volatile uint32_t latency_max;
- volatile uint32_t latency_total;
- volatile uint32_t latency_count;
-#endif
-
- volatile uint32_t cloud_req_recvd;
- volatile uint32_t cloud_req_err;
-
- // query types.
- volatile uint32_t queries_per_type[ACLK_QUERY_TYPE_COUNT];
-
- // HTTP-specific request types.
- volatile uint32_t cloud_req_http_by_type[ACLK_STATS_CLOUD_HTTP_REQ_TYPE_CNT];
-
- volatile uint32_t cloud_q_process_total;
- volatile uint32_t cloud_q_process_count;
- volatile uint32_t cloud_q_process_max;
-} aclk_metrics_per_sample;
-
-extern uint32_t *aclk_proto_rx_msgs_sample;
-
-extern uint32_t *aclk_queries_per_thread;
-
-void *aclk_stats_main_thread(void *ptr);
-void aclk_stats_thread_prepare(int query_thread_count, unsigned int proto_hdl_cnt);
-void aclk_stats_thread_cleanup();
-void aclk_stats_upd_online(int online);
-
-#ifdef NETDATA_INTERNAL_CHECKS
-void aclk_stats_msg_published(uint16_t id);
-void aclk_stats_msg_puback(uint16_t id);
-#endif /* NETDATA_INTERNAL_CHECKS */
-
-#endif /* NETDATA_ACLK_STATS_H */
diff --git a/src/aclk/aclk_tx_msgs.c b/src/aclk/aclk_tx_msgs.c
index c1ed68052..2d256279e 100644
--- a/src/aclk/aclk_tx_msgs.c
+++ b/src/aclk/aclk_tx_msgs.c
@@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "aclk_tx_msgs.h"
-#include "daemon/common.h"
#include "aclk_util.h"
-#include "aclk_stats.h"
#include "aclk.h"
#include "aclk_capas.h"
@@ -13,9 +11,6 @@
#pragma region aclk_tx_msgs helper functions
#endif
-// version for aclk legacy (old cloud arch)
-#define ACLK_VERSION 2
-
static void freez_aclk_publish5a(void *ptr) {
freez(ptr);
}
@@ -23,6 +18,8 @@ static void freez_aclk_publish5b(void *ptr) {
freez(ptr);
}
+#define ACLK_HEADER_VERSION (2)
+
uint16_t aclk_send_bin_message_subtopic_pid(mqtt_wss_client client, char *msg, size_t msg_len, enum aclk_topics subtopic, const char *msgname)
{
#ifndef ACLK_LOG_CONVERSATION_DIR
@@ -38,10 +35,6 @@ uint16_t aclk_send_bin_message_subtopic_pid(mqtt_wss_client client, char *msg, s
mqtt_wss_publish5(client, (char*)topic, NULL, msg, &freez_aclk_publish5a, msg_len, MQTT_WSS_PUB_QOS1, &packet_id);
-#ifdef NETDATA_INTERNAL_CHECKS
- aclk_stats_msg_published(packet_id);
-#endif
-
if (aclklog_enabled) {
char *json = protomsg_to_json(msg, msg_len, msgname);
log_aclk_message_bin(json, strlen(json), 1, topic, msgname);
@@ -51,14 +44,13 @@ uint16_t aclk_send_bin_message_subtopic_pid(mqtt_wss_client client, char *msg, s
return packet_id;
}
-#define TOPIC_MAX_LEN 512
#define V2_BIN_PAYLOAD_SEPARATOR "\x0D\x0A\x0D\x0A"
-static int aclk_send_message_with_bin_payload(mqtt_wss_client client, json_object *msg, const char *topic, const void *payload, size_t payload_len)
+static short aclk_send_message_with_bin_payload(mqtt_wss_client client, json_object *msg, const char *topic, const void *payload, size_t payload_len)
{
uint16_t packet_id;
const char *str;
char *full_msg = NULL;
- int len;
+ size_t len;
if (unlikely(!topic || topic[0] != '/')) {
netdata_log_error("Full topic required!");
@@ -78,20 +70,16 @@ static int aclk_send_message_with_bin_payload(mqtt_wss_client client, json_objec
json_object_put(msg);
if (payload_len) {
- memcpy(&full_msg[len], V2_BIN_PAYLOAD_SEPARATOR, strlen(V2_BIN_PAYLOAD_SEPARATOR));
+ memcpy(&full_msg[len], V2_BIN_PAYLOAD_SEPARATOR, sizeof(V2_BIN_PAYLOAD_SEPARATOR) - 1);
len += strlen(V2_BIN_PAYLOAD_SEPARATOR);
memcpy(&full_msg[len], payload, payload_len);
}
int rc = mqtt_wss_publish5(client, (char*)topic, NULL, full_msg, &freez_aclk_publish5b, full_msg_len, MQTT_WSS_PUB_QOS1, &packet_id);
- if (rc == MQTT_WSS_ERR_TOO_BIG_FOR_SERVER)
+ if (rc == MQTT_WSS_ERR_MSG_TOO_BIG)
return HTTP_RESP_CONTENT_TOO_LONG;
-#ifdef NETDATA_INTERNAL_CHECKS
- aclk_stats_msg_published(packet_id);
-#endif
-
return 0;
}
@@ -99,12 +87,14 @@ static int aclk_send_message_with_bin_payload(mqtt_wss_client client, json_objec
* Creates universal header common for all ACLK messages. User gets ownership of json object created.
* Usually this is freed by send function after message has been sent.
*/
-static struct json_object *create_hdr(const char *type, const char *msg_id, time_t ts_secs, usec_t ts_us, int version)
+static struct json_object *create_hdr(const char *type, const char *msg_id)
{
nd_uuid_t uuid;
- char uuid_str[36 + 1];
+ char uuid_str[UUID_STR_LEN];
json_object *tmp;
json_object *obj = json_object_new_object();
+ time_t ts_secs;
+ usec_t ts_us;
tmp = json_object_new_string(type);
json_object_object_add(obj, "type", tmp);
@@ -115,11 +105,9 @@ static struct json_object *create_hdr(const char *type, const char *msg_id, time
msg_id = uuid_str;
}
- if (ts_secs == 0) {
- ts_us = now_realtime_usec();
- ts_secs = ts_us / USEC_PER_SEC;
- ts_us = ts_us % USEC_PER_SEC;
- }
+ ts_us = now_realtime_usec();
+ ts_secs = ts_us / USEC_PER_SEC;
+ ts_us = ts_us % USEC_PER_SEC;
tmp = json_object_new_string(msg_id);
json_object_object_add(obj, "msg-id", tmp);
@@ -144,7 +132,7 @@ static struct json_object *create_hdr(const char *type, const char *msg_id, time
tmp = json_object_new_int64(aclk_session_us);
json_object_object_add(obj, "connect-offset-usec", tmp);
- tmp = json_object_new_int(version);
+ tmp = json_object_new_int(ACLK_HEADER_VERSION);
json_object_object_add(obj, "version", tmp);
return obj;
@@ -161,7 +149,7 @@ static struct json_object *create_hdr(const char *type, const char *msg_id, time
void aclk_http_msg_v2_err(mqtt_wss_client client, const char *topic, const char *msg_id, int http_code, int ec, const char* emsg, const char *payload, size_t payload_len)
{
json_object *tmp, *msg;
- msg = create_hdr("http", msg_id, 0, 0, 2);
+ msg = create_hdr("http", msg_id);
tmp = json_object_new_int(http_code);
json_object_object_add(msg, "http-code", tmp);
@@ -176,11 +164,12 @@ void aclk_http_msg_v2_err(mqtt_wss_client client, const char *topic, const char
}
}
-int aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_id, usec_t t_exec, usec_t created, int http_code, const char *payload, size_t payload_len)
+short aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_id, usec_t t_exec, usec_t created,
+ short http_code, const char *payload, size_t payload_len)
{
json_object *tmp, *msg;
- msg = create_hdr("http", msg_id, 0, 0, 2);
+ msg = create_hdr("http", msg_id);
tmp = json_object_new_int64(t_exec);
json_object_object_add(msg, "t-exec", tmp);
@@ -191,7 +180,7 @@ int aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_
tmp = json_object_new_int(http_code);
json_object_object_add(msg, "http-code", tmp);
- int rc = aclk_send_message_with_bin_payload(client, msg, topic, payload, payload_len);
+ short rc = aclk_send_message_with_bin_payload(client, msg, topic, payload, payload_len);
switch (rc) {
case HTTP_RESP_CONTENT_TOO_LONG:
@@ -200,12 +189,11 @@ int aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_
case HTTP_RESP_INTERNAL_SERVER_ERROR:
aclk_http_msg_v2_err(client, topic, msg_id, rc, CLOUD_EC_FAIL_TOPIC, CLOUD_EMSG_FAIL_TOPIC, payload, payload_len);
break;
- case HTTP_RESP_GATEWAY_TIMEOUT:
- case HTTP_RESP_SERVICE_UNAVAILABLE:
- aclk_http_msg_v2_err(client, topic, msg_id, rc, CLOUD_EC_SND_TIMEOUT, CLOUD_EMSG_SND_TIMEOUT, payload, payload_len);
+ default:
+ rc = http_code;
break;
}
- return rc ? rc : http_code;
+ return rc;
}
uint16_t aclk_send_agent_connection_update(mqtt_wss_client client, int reachable) {
@@ -219,19 +207,19 @@ uint16_t aclk_send_agent_connection_update(mqtt_wss_client client, int reachable
.capabilities = aclk_get_agent_capas()
};
- rrdhost_aclk_state_lock(localhost);
- if (unlikely(!localhost->aclk_state.claimed_id)) {
+ CLAIM_ID claim_id = claim_id_get();
+ if (unlikely(!claim_id_is_set(claim_id))) {
netdata_log_error("Internal error. Should not come here if not claimed");
- rrdhost_aclk_state_unlock(localhost);
return 0;
}
- if (localhost->aclk_state.prev_claimed_id)
- conn.claim_id = localhost->aclk_state.prev_claimed_id;
+
+ CLAIM_ID previous_claim_id = claim_id_get_last_working();
+ if (claim_id_is_set(previous_claim_id))
+ conn.claim_id = previous_claim_id.str;
else
- conn.claim_id = localhost->aclk_state.claimed_id;
+ conn.claim_id = claim_id.str;
char *msg = generate_update_agent_connection(&len, &conn);
- rrdhost_aclk_state_unlock(localhost);
if (!msg) {
netdata_log_error("Error generating agent::v1::UpdateAgentConnection payload");
@@ -239,10 +227,9 @@ uint16_t aclk_send_agent_connection_update(mqtt_wss_client client, int reachable
}
pid = aclk_send_bin_message_subtopic_pid(client, msg, len, ACLK_TOPICID_AGENT_CONN, "UpdateAgentConnection");
- if (localhost->aclk_state.prev_claimed_id) {
- freez(localhost->aclk_state.prev_claimed_id);
- localhost->aclk_state.prev_claimed_id = NULL;
- }
+ if (claim_id_is_set(previous_claim_id))
+ claim_id_clear_previous_working();
+
return pid;
}
@@ -254,16 +241,14 @@ char *aclk_generate_lwt(size_t *size) {
.capabilities = NULL
};
- rrdhost_aclk_state_lock(localhost);
- if (unlikely(!localhost->aclk_state.claimed_id)) {
+ CLAIM_ID claim_id = claim_id_get();
+ if(!claim_id_is_set(claim_id)) {
netdata_log_error("Internal error. Should not come here if not claimed");
- rrdhost_aclk_state_unlock(localhost);
return NULL;
}
- conn.claim_id = localhost->aclk_state.claimed_id;
+ conn.claim_id = claim_id.str;
char *msg = generate_update_agent_connection(size, &conn);
- rrdhost_aclk_state_unlock(localhost);
if (!msg)
netdata_log_error("Error generating agent::v1::UpdateAgentConnection payload for LWT");
diff --git a/src/aclk/aclk_tx_msgs.h b/src/aclk/aclk_tx_msgs.h
index 86ed20c38..6b11996d1 100644
--- a/src/aclk/aclk_tx_msgs.h
+++ b/src/aclk/aclk_tx_msgs.h
@@ -4,7 +4,6 @@
#include <json-c/json.h>
#include "libnetdata/libnetdata.h"
-#include "daemon/common.h"
#include "mqtt_websockets/mqtt_wss_client.h"
#include "schema-wrappers/schema_wrappers.h"
#include "aclk_util.h"
@@ -12,7 +11,8 @@
uint16_t aclk_send_bin_message_subtopic_pid(mqtt_wss_client client, char *msg, size_t msg_len, enum aclk_topics subtopic, const char *msgname);
void aclk_http_msg_v2_err(mqtt_wss_client client, const char *topic, const char *msg_id, int http_code, int ec, const char* emsg, const char *payload, size_t payload_len);
-int aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_id, usec_t t_exec, usec_t created, int http_code, const char *payload, size_t payload_len);
+short aclk_http_msg_v2(mqtt_wss_client client, const char *topic, const char *msg_id, usec_t t_exec, usec_t created,
+ short http_code, const char *payload, size_t payload_len);
uint16_t aclk_send_agent_connection_update(mqtt_wss_client client, int reachable);
char *aclk_generate_lwt(size_t *size);
diff --git a/src/aclk/aclk_util.c b/src/aclk/aclk_util.c
index 3bf2e3f18..d01fa8f2c 100644
--- a/src/aclk/aclk_util.c
+++ b/src/aclk/aclk_util.c
@@ -2,8 +2,6 @@
#include "aclk_util.h"
-#ifdef ENABLE_ACLK
-
#include "aclk_proxy.h"
#include "daemon/common.h"
@@ -12,8 +10,6 @@ usec_t aclk_session_newarch = 0;
aclk_env_t *aclk_env = NULL;
-int chart_batch_id;
-
aclk_encoding_type_t aclk_encoding_type_t_from_str(const char *str) {
if (!strcmp(str, "json")) {
return ACLK_ENC_JSON;
@@ -186,20 +182,18 @@ static void topic_generate_final(struct aclk_topic *t) {
if (!replace_tag)
return;
- rrdhost_aclk_state_lock(localhost);
- if (unlikely(!localhost->aclk_state.claimed_id)) {
+ CLAIM_ID claim_id = claim_id_get();
+ if (unlikely(!claim_id_is_set(claim_id))) {
netdata_log_error("This should never be called if agent not claimed");
- rrdhost_aclk_state_unlock(localhost);
return;
}
- t->topic = mallocz(strlen(t->topic_recvd) + 1 - strlen(CLAIM_ID_REPLACE_TAG) + strlen(localhost->aclk_state.claimed_id));
+ t->topic = mallocz(strlen(t->topic_recvd) + 1 - strlen(CLAIM_ID_REPLACE_TAG) + strlen(claim_id.str));
memcpy(t->topic, t->topic_recvd, replace_tag - t->topic_recvd);
dest = t->topic + (replace_tag - t->topic_recvd);
- memcpy(dest, localhost->aclk_state.claimed_id, strlen(localhost->aclk_state.claimed_id));
- dest += strlen(localhost->aclk_state.claimed_id);
- rrdhost_aclk_state_unlock(localhost);
+ memcpy(dest, claim_id.str, strlen(claim_id.str));
+ dest += strlen(claim_id.str);
replace_tag += strlen(CLAIM_ID_REPLACE_TAG);
strcpy(dest, replace_tag);
dest += strlen(replace_tag);
@@ -315,7 +309,7 @@ const char *aclk_get_topic(enum aclk_topics topic)
* having to resort to callbacks.
*/
-const char *aclk_topic_cache_iterate(aclk_topic_cache_iter_t *iter)
+const char *aclk_topic_cache_iterate(size_t *iter)
{
if (!aclk_topic_cache) {
netdata_log_error("Topic cache not initialized when %s was called.", __FUNCTION__);
@@ -348,15 +342,13 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un
attempt++;
- if (attempt == 0) {
- srandom(time(NULL));
+ if (attempt == 0)
return 0;
- }
unsigned long int delay = pow(base, attempt - 1);
delay *= MSEC_PER_SEC;
- delay += (random() % (MAX(1000, delay/2)));
+ delay += (os_random32() % (MAX(1000, delay/2)));
if (delay <= min * MSEC_PER_SEC)
return min;
@@ -440,45 +432,3 @@ void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt
freez(proxy);
}
-#endif /* ENABLE_ACLK */
-
-#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
-static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
-{
- EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
-
- if (ctx != NULL) {
- memset(ctx, 0, sizeof(*ctx));
- }
- return ctx;
-}
-static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
-{
- OPENSSL_free(ctx);
- return;
-}
-#endif
-
-int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
-{
- int len;
- unsigned char *str = out;
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- EVP_EncodeInit(ctx);
- EVP_EncodeUpdate(ctx, str, outl, in, in_len);
- str += *outl;
- EVP_EncodeFinal(ctx, str, &len);
- *outl += len;
-
- str = out;
- while(*str) {
- if (*str != 0x0D && *str != 0x0A)
- *out++ = *str++;
- else
- str++;
- }
- *out = 0;
-
- EVP_ENCODE_CTX_free(ctx);
- return 0;
-}
diff --git a/src/aclk/aclk_util.h b/src/aclk/aclk_util.h
index 6c0239cc3..24e179964 100644
--- a/src/aclk/aclk_util.h
+++ b/src/aclk/aclk_util.h
@@ -3,8 +3,6 @@
#define ACLK_UTIL_H
#include "libnetdata/libnetdata.h"
-
-#ifdef ENABLE_ACLK
#include "mqtt_websockets/mqtt_wss_client.h"
#define CLOUD_EC_MALFORMED_NODE_ID 1
@@ -95,15 +93,10 @@ enum aclk_topics {
ACLK_TOPICID_CTXS_UPDATED = 20
};
-typedef size_t aclk_topic_cache_iter_t;
-#define ACLK_TOPIC_CACHE_ITER_T_INITIALIZER (0)
-
const char *aclk_get_topic(enum aclk_topics topic);
-int aclk_generate_topic_cache(struct json_object *json);
+int aclk_generate_topic_cache(json_object *json);
void free_topic_cache(void);
-const char *aclk_topic_cache_iterate(aclk_topic_cache_iter_t *iter);
-// TODO
-// aclk_topics_reload //when claim id changes
+const char *aclk_topic_cache_iterate(size_t *iter);
#ifdef ACLK_LOG_CONVERSATION_DIR
extern volatile int aclk_conversation_log_counter;
@@ -114,8 +107,5 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un
#define aclk_tbeb_reset(x) aclk_tbeb_delay(1, 0, 0, 0)
void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type);
-#endif /* ENABLE_ACLK */
-
-int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len);
#endif /* ACLK_UTIL_H */
diff --git a/src/aclk/helpers/mqtt_wss_pal.h b/src/aclk/helpers/mqtt_wss_pal.h
deleted file mode 100644
index fe1aacf49..000000000
--- a/src/aclk/helpers/mqtt_wss_pal.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#ifndef MQTT_WSS_PAL_H
-#define MQTT_WSS_PAL_H
-
-#include "libnetdata/libnetdata.h"
-
-#undef OPENSSL_VERSION_095
-#undef OPENSSL_VERSION_097
-#undef OPENSSL_VERSION_110
-#undef OPENSSL_VERSION_111
-
-#endif /* MQTT_WSS_PAL_H */
diff --git a/src/aclk/helpers/ringbuffer_pal.h b/src/aclk/helpers/ringbuffer_pal.h
deleted file mode 100644
index 2f7e1cb93..000000000
--- a/src/aclk/helpers/ringbuffer_pal.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#ifndef RINGBUFFER_PAL_H
-#define RINGBUFFER_PAL_H
-
-#include "libnetdata/libnetdata.h"
-
-#define crbuf_malloc(...) mallocz(__VA_ARGS__)
-#define crbuf_free(...) freez(__VA_ARGS__)
-
-#endif /* RINGBUFFER_PAL_H */
diff --git a/src/aclk/https_client.c b/src/aclk/https_client.c
index 4a0362992..f144eaf15 100644
--- a/src/aclk/https_client.c
+++ b/src/aclk/https_client.c
@@ -105,7 +105,8 @@ static int parse_http_hdr(rbuf_t buf, http_parse_ctx *parse_ctx)
int idx, idx_end;
char buf_key[HTTP_HDR_BUFFER_SIZE];
char buf_val[HTTP_HDR_BUFFER_SIZE];
- char *ptr = buf_key;
+ char *ptr;
+
if (!rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx_end)) {
netdata_log_error("CRLF expected");
return 1;
@@ -555,7 +556,7 @@ static int handle_http_request(https_req_ctx_t *ctx) {
// we remove those but during encoding we need that space in the buffer
creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n");
char *creds_base64 = callocz(1, creds_base64_len + 1);
- base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len);
+ (void) netdata_base64_encode((unsigned char *)creds_base64, (unsigned char *)creds_plain, creds_plain_len);
buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64);
freez(creds_plain);
}
@@ -583,7 +584,6 @@ static int handle_http_request(https_req_ctx_t *ctx) {
if (ctx->parse_ctx.chunked_response)
freez(ctx->parse_ctx.chunked_response);
rc = 4;
- goto err_exit;
}
err_exit:
diff --git a/src/aclk/https_client.h b/src/aclk/https_client.h
index cf14ffd87..b1445a5b7 100644
--- a/src/aclk/https_client.h
+++ b/src/aclk/https_client.h
@@ -5,9 +5,6 @@
#include "libnetdata/libnetdata.h"
-#include "mqtt_websockets/c-rbuf/cringbuffer.h"
-#include "mqtt_websockets/c_rhash/c_rhash.h"
-
typedef enum http_req_type {
HTTP_REQ_GET = 0,
HTTP_REQ_POST,
diff --git a/src/aclk/mqtt_websockets/.github/workflows/run-tests.yaml b/src/aclk/mqtt_websockets/.github/workflows/run-tests.yaml
deleted file mode 100644
index da5dde821..000000000
--- a/src/aclk/mqtt_websockets/.github/workflows/run-tests.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-name: run-tests
-on:
- push:
- schedule:
- - cron: '5 3 * * 0'
- pull_request:
-jobs:
- run-tests:
- runs-on: ubuntu-latest
- steps:
- - name: Install ruby and deps
- run: sudo apt-get install ruby ruby-dev mosquitto
- - name: Checkout
- uses: actions/checkout@v2
diff --git a/src/aclk/mqtt_websockets/.gitignore b/src/aclk/mqtt_websockets/.gitignore
deleted file mode 100644
index 9f1a0d89a..000000000
--- a/src/aclk/mqtt_websockets/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-build/*
-!build/.keep
-test
-.vscode
-mqtt/mqtt.c
-mqtt/include/mqtt.h
-libmqttwebsockets.*
-*.o
-.dirstamp
-.deps
diff --git a/src/aclk/mqtt_websockets/README.md b/src/aclk/mqtt_websockets/README.md
index b159686df..9507fedb5 100644
--- a/src/aclk/mqtt_websockets/README.md
+++ b/src/aclk/mqtt_websockets/README.md
@@ -4,4 +4,4 @@ Library to connect MQTT client over Websockets Secure (WSS).
## License
-The Project is released under GPL v3 license. See [License](LICENSE)
+The Project is released under GPL v3 license. See [License](/LICENSE)
diff --git a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.c b/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.c
deleted file mode 100644
index 8950c6906..000000000
--- a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.c
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include "cringbuffer.h"
-#include "cringbuffer_internal.h"
-
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-// this allows user to use their own
-// custom memory allocation functions
-#ifdef RBUF_CUSTOM_MALLOC
-#include "../../helpers/ringbuffer_pal.h"
-#else
-#define crbuf_malloc(...) malloc(__VA_ARGS__)
-#define crbuf_free(...) free(__VA_ARGS__)
-#endif
-
-rbuf_t rbuf_create(size_t size)
-{
- rbuf_t buffer = crbuf_malloc(sizeof(struct rbuf_t) + size);
- if (!buffer)
- return NULL;
-
- memset(buffer, 0, sizeof(struct rbuf_t));
-
- buffer->data = ((char*)buffer) + sizeof(struct rbuf_t);
-
- buffer->head = buffer->data;
- buffer->tail = buffer->data;
- buffer->size = size;
- buffer->end = buffer->data + size;
-
- return buffer;
-}
-
-void rbuf_free(rbuf_t buffer)
-{
- crbuf_free(buffer);
-}
-
-void rbuf_flush(rbuf_t buffer)
-{
- buffer->head = buffer->data;
- buffer->tail = buffer->data;
- buffer->size_data = 0;
-}
-
-char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes)
-{
- *bytes = 0;
- if (buffer->head == buffer->tail && buffer->size_data)
- return NULL;
-
- *bytes = ((buffer->head >= buffer->tail) ? buffer->end : buffer->tail) - buffer->head;
- return buffer->head;
-}
-
-char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes)
-{
- *bytes = 0;
- if(buffer->head == buffer->tail && !buffer->size_data)
- return NULL;
-
- *bytes = ((buffer->tail >= buffer->head) ? buffer->end : buffer->head) - buffer->tail;
-
- return buffer->tail;
-}
-
-int rbuf_bump_head(rbuf_t buffer, size_t bytes)
-{
- size_t free_bytes = rbuf_bytes_free(buffer);
- if (bytes > free_bytes)
- return 0;
- int i = buffer->head - buffer->data;
- buffer->head = &buffer->data[(i + bytes) % buffer->size];
- buffer->size_data += bytes;
- return 1;
-}
-
-int rbuf_bump_tail(rbuf_t buffer, size_t bytes)
-{
- if(!rbuf_bump_tail_noopt(buffer, bytes))
- return 0;
-
- // if tail catched up with head
- // start writing buffer from beggining
- // this is not necessary (rbuf must work well without it)
- // but helps to optimize big writes as rbuf_get_linear_insert_range
- // will return bigger continuous region
- if(buffer->tail == buffer->head) {
- assert(buffer->size_data == 0);
- rbuf_flush(buffer);
- }
-
- return 1;
-}
-
-size_t rbuf_get_capacity(rbuf_t buffer)
-{
- return buffer->size;
-}
-
-size_t rbuf_bytes_available(rbuf_t buffer)
-{
- return buffer->size_data;
-}
-
-size_t rbuf_bytes_free(rbuf_t buffer)
-{
- return buffer->size - buffer->size_data;
-}
-
-size_t rbuf_push(rbuf_t buffer, const char *data, size_t len)
-{
- size_t to_cpy;
- char *w_ptr = rbuf_get_linear_insert_range(buffer, &to_cpy);
- if(!to_cpy)
- return to_cpy;
-
- to_cpy = MIN(to_cpy, len);
- memcpy(w_ptr, data, to_cpy);
- rbuf_bump_head(buffer, to_cpy);
- if(to_cpy < len)
- to_cpy += rbuf_push(buffer, &data[to_cpy], len - to_cpy);
- return to_cpy;
-}
-
-size_t rbuf_pop(rbuf_t buffer, char *data, size_t len)
-{
- size_t to_cpy;
- const char *r_ptr = rbuf_get_linear_read_range(buffer, &to_cpy);
- if(!to_cpy)
- return to_cpy;
-
- to_cpy = MIN(to_cpy, len);
- memcpy(data, r_ptr, to_cpy);
- rbuf_bump_tail(buffer, to_cpy);
- if(to_cpy < len)
- to_cpy += rbuf_pop(buffer, &data[to_cpy], len - to_cpy);
- return to_cpy;
-}
-
-static inline void rbuf_ptr_inc(rbuf_t buffer, const char **ptr)
-{
- (*ptr)++;
- if(*ptr >= buffer->end)
- *ptr = buffer->data;
-}
-
-int rbuf_memcmp(rbuf_t buffer, const char *haystack, const char *needle, size_t needle_bytes)
-{
- const char *end = needle + needle_bytes;
-
- // as head==tail can mean 2 things here
- if (haystack == buffer->head && buffer->size_data) {
- if (*haystack != *needle)
- return (*haystack - *needle);
- rbuf_ptr_inc(buffer, &haystack);
- needle++;
- }
-
- while (haystack != buffer->head && needle != end) {
- if (*haystack != *needle)
- return (*haystack - *needle);
- rbuf_ptr_inc(buffer, &haystack);
- needle++;
- }
- return 0;
-}
-
-int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes)
-{
- return rbuf_memcmp(buffer, buffer->tail, to_cmp, to_cmp_bytes);
-}
-
-char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx)
-{
- const char *ptr = buffer->tail;
- *found_idx = 0;
-
- if (!rbuf_bytes_available(buffer))
- return NULL;
-
- if (buffer->head == buffer->tail && buffer->size_data) {
- if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
- return (char *)ptr;
- rbuf_ptr_inc(buffer, &ptr);
- (*found_idx)++;
- }
-
- while (ptr != buffer->head)
- {
- if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
- return (char *)ptr;
- rbuf_ptr_inc(buffer, &ptr);
- (*found_idx)++;
- }
- return NULL;
-}
diff --git a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.h b/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.h
deleted file mode 100644
index eb98035a9..000000000
--- a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#ifndef CRINGBUFFER_H
-#define CRINGBUFFER_H
-
-#include <stddef.h>
-
-typedef struct rbuf_t *rbuf_t;
-
-rbuf_t rbuf_create(size_t size);
-void rbuf_free(rbuf_t buffer);
-void rbuf_flush(rbuf_t buffer);
-
-/* /param bytes how much bytes can be copied into pointer returned
- * /return pointer where data can be copied to or NULL if buffer full
- */
-char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes);
-char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes);
-
-int rbuf_bump_head(rbuf_t buffer, size_t bytes);
-int rbuf_bump_tail(rbuf_t buffer, size_t bytes);
-
-/* @param buffer related buffer instance
- * @returns total capacity of buffer in bytes (not free/used)
- */
-size_t rbuf_get_capacity(rbuf_t buffer);
-
-/* @param buffer related buffer instance
- * @returns count of bytes stored in the buffer
- */
-size_t rbuf_bytes_available(rbuf_t buffer);
-
-/* @param buffer related buffer instance
- * @returns count of bytes available/free in the buffer (how many more bytes you can store in this buffer)
- */
-size_t rbuf_bytes_free(rbuf_t buffer);
-
-/* writes as many bytes from `data` into the `buffer` as possible
- * but maximum `len` bytes
- */
-size_t rbuf_push(rbuf_t buffer, const char *data, size_t len);
-size_t rbuf_pop(rbuf_t buffer, char *data, size_t len);
-
-char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx);
-int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes);
-
-#endif
diff --git a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h b/src/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h
deleted file mode 100644
index d32de187c..000000000
--- a/src/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#ifndef CRINGBUFFER_INTERNAL_H
-#define CRINGBUFFER_INTERNAL_H
-
-struct rbuf_t {
- char *data;
-
- // points to next byte where we can write
- char *head;
- // points to oldest (next to be poped) readable byte
- char *tail;
-
- // to avoid calculating data + size
- // all the time
- char *end;
-
- size_t size;
- size_t size_data;
-};
-
-/* this exists so that it can be tested by unit tests
- * without optimization that resets head and tail to
- * beginning if buffer empty
- */
-inline static int rbuf_bump_tail_noopt(rbuf_t buffer, size_t bytes)
-{
- if (bytes > buffer->size_data)
- return 0;
- int i = buffer->tail - buffer->data;
- buffer->tail = &buffer->data[(i + bytes) % buffer->size];
- buffer->size_data -= bytes;
-
- return 1;
-}
-
-#endif
diff --git a/src/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c b/src/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c
deleted file mode 100644
index 6a17c9956..000000000
--- a/src/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c
+++ /dev/null
@@ -1,485 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include "ringbuffer.h"
-
-// to be able to access internals
-// never do this from app
-#include "../src/ringbuffer_internal.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#define KNRM "\x1B[0m"
-#define KRED "\x1B[31m"
-#define KGRN "\x1B[32m"
-#define KYEL "\x1B[33m"
-#define KBLU "\x1B[34m"
-#define KMAG "\x1B[35m"
-#define KCYN "\x1B[36m"
-#define KWHT "\x1B[37m"
-
-#define UNUSED(x) (void)(x)
-
-int total_fails = 0;
-int total_tests = 0;
-int total_checks = 0;
-
-#define CHECK_EQ_RESULT(x, y) \
- while (s_len--) \
- putchar('.'); \
- printf("%s%s " KNRM "\n", (((x) == (y)) ? KGRN : KRED), (((x) == (y)) ? " PASS " : " FAIL ")); \
- if ((x) != (y)) \
- total_fails++; \
- total_checks++;
-
-#define CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ...) \
- { \
- int s_len = \
- 100 - \
- printf(("Checking: " KWHT "%s %s%2d " subtest_name " " KNRM), __func__, prefix, subtest_no, ##__VA_ARGS__); \
- CHECK_EQ_RESULT(x, y) \
- }
-
-#define CHECK_EQ(x, y, subtest_name, ...) \
- { \
- int s_len = \
- 100 - printf(("Checking: " KWHT "%s %2d " subtest_name " " KNRM), __func__, subtest_no, ##__VA_ARGS__); \
- CHECK_EQ_RESULT(x, y) \
- }
-
-#define TEST_DECL() \
- int subtest_no = 0; \
- printf(KYEL "TEST SUITE: %s\n" KNRM, __func__); \
- total_tests++;
-
-static void test_rbuf_get_linear_insert_range()
-{
- TEST_DECL();
-
- // check empty buffer behaviour
- rbuf_t buff = rbuf_create(5);
- char *to_write;
- size_t ret;
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(ret, 5, "empty size");
- CHECK_EQ(to_write, buff->head, "empty write ptr");
- rbuf_free(buff);
-
- // check full buffer behaviour
- subtest_no++;
- buff = rbuf_create(5);
- ret = rbuf_bump_head(buff, 5);
- CHECK_EQ(ret, 1, "ret");
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(to_write, NULL, "writable NULL");
- CHECK_EQ(ret, 0, "writable count = 0");
-
- // check buffer flush
- subtest_no++;
- rbuf_flush(buff);
- CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check behaviour head > tail
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 3);
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(to_write, buff->head, "write location");
- CHECK_EQ(ret, 2, "availible to linear write");
-
- // check behaviour tail > head
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 5);
- rbuf_bump_tail(buff, 3);
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 3, "tail_ptr");
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(to_write, buff->head, "write location");
- CHECK_EQ(ret, 3, "availible to linear write");
-
-/* // check behaviour tail and head at last element
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 4);
- rbuf_bump_tail(buff, 4);
- CHECK_EQ(buff->head, buff->end - 1, "head_ptr");
- CHECK_EQ(buff->tail, buff->end - 1, "tail_ptr");
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(to_write, buff->head, "write location");
- CHECK_EQ(ret, 1, "availible to linear write");*/
-
- // check behaviour tail and head at last element
- // after rbuf_bump_tail optimisation that restarts buffer
- // in case tail catches up with head
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 4);
- rbuf_bump_tail(buff, 4);
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
- to_write = rbuf_get_linear_insert_range(buff, &ret);
- CHECK_EQ(to_write, buff->head, "write location");
- CHECK_EQ(ret, 5, "availible to linear write");
-}
-
-#define _CHECK_EQ(x, y, subtest_name, ...) CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ##__VA_ARGS__)
-#define _PREFX "(size = %5zu) "
-static void test_rbuf_bump_head_bsize(size_t size)
-{
- char prefix[16];
- snprintf(prefix, 16, _PREFX, size);
- int subtest_no = 0;
- rbuf_t buff = rbuf_create(size);
- _CHECK_EQ(rbuf_bytes_free(buff), size, "size_free");
-
- subtest_no++;
- int ret = rbuf_bump_head(buff, size);
- _CHECK_EQ(buff->data, buff->head, "loc");
- _CHECK_EQ(ret, 1, "ret");
- _CHECK_EQ(buff->size_data, buff->size, "size");
- _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
-
- subtest_no++;
- ret = rbuf_bump_head(buff, 1);
- _CHECK_EQ(buff->data, buff->head, "loc no move");
- _CHECK_EQ(ret, 0, "ret error");
- _CHECK_EQ(buff->size_data, buff->size, "size");
- _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
- rbuf_free(buff);
-
- subtest_no++;
- buff = rbuf_create(size);
- ret = rbuf_bump_head(buff, size - 1);
- _CHECK_EQ(buff->head, buff->end-1, "loc end");
- rbuf_free(buff);
-}
-#undef _CHECK_EQ
-
-static void test_rbuf_bump_head()
-{
- TEST_DECL();
- UNUSED(subtest_no);
-
- size_t test_sizes[] = { 1, 2, 3, 5, 6, 7, 8, 100, 99999, 0 };
- for (int i = 0; test_sizes[i]; i++)
- test_rbuf_bump_head_bsize(test_sizes[i]);
-}
-
-static void test_rbuf_bump_tail_noopt(int subtest_no)
-{
- rbuf_t buff = rbuf_create(10);
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
-
- subtest_no++;
- int ret = rbuf_bump_head(buff, 5);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free");
- CHECK_EQ(rbuf_bytes_available(buff), 5, "size_avail");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 2);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 3, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 7, "size_free");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 2, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 3);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 1);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_head(buff, 7);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 7, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 3, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 5);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check tail can't overrun head
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 3);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check head can't overrun tail
- subtest_no++;
- ret = rbuf_bump_head(buff, 9);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check head can fill the buffer
- subtest_no++;
- ret = rbuf_bump_head(buff, 8);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 10, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check can empty the buffer
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 10);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-}
-
-static void test_rbuf_bump_tail_opt(int subtest_no)
-{
- subtest_no++;
- rbuf_t buff = rbuf_create(10);
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
-
- subtest_no++;
- int ret = rbuf_bump_head(buff, 5);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free");
- CHECK_EQ(rbuf_bytes_available(buff), 5, "size_avail");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail(buff, 2);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 3, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 7, "size_free");
- CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 2, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail(buff, 3);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail_noopt(buff, 1);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_head(buff, 6);
- ret = rbuf_bump_tail(buff, 5);
- ret = rbuf_bump_head(buff, 6);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 7, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 3, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
-
- subtest_no++;
- ret = rbuf_bump_tail(buff, 5);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check tail can't overrun head
- subtest_no++;
- ret = rbuf_bump_tail(buff, 3);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check head can't overrun tail
- subtest_no++;
- ret = rbuf_bump_head(buff, 9);
- CHECK_EQ(ret, 0, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
- CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check head can fill the buffer
- subtest_no++;
- ret = rbuf_bump_head(buff, 8);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 10, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-
- // check can empty the buffer
- subtest_no++;
- ret = rbuf_bump_tail(buff, 10);
- CHECK_EQ(ret, 1, "ret");
- CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
- CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
- CHECK_EQ(buff->head, buff->data, "head_ptr");
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
-}
-
-static void test_rbuf_bump_tail()
-{
- TEST_DECL();
- test_rbuf_bump_tail_noopt(subtest_no);
- test_rbuf_bump_tail_opt(subtest_no);
-}
-
-#define ASCII_A 0x61
-#define ASCII_Z 0x7A
-#define TEST_DATA_SIZE ASCII_Z-ASCII_A+1
-static void test_rbuf_push()
-{
- TEST_DECL();
- rbuf_t buff = rbuf_create(10);
- int i;
- char test_data[TEST_DATA_SIZE];
-
- for (int i = 0; i <= TEST_DATA_SIZE; i++)
- test_data[i] = i + ASCII_A;
-
- int ret = rbuf_push(buff, test_data, 10);
- CHECK_EQ(ret, 10, "written 10 bytes");
- CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], i + ASCII_A, "Check data");
-
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 5);
- rbuf_bump_tail_noopt(buff, 5); //to not reset both pointers to beginning
- ret = rbuf_push(buff, test_data, 10);
- CHECK_EQ(ret, 10, "written 10 bytes");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], ((i+5)%10) + ASCII_A, "Check Data");
-
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 9);
- rbuf_bump_tail_noopt(buff, 9);
- ret = rbuf_push(buff, test_data, 10);
- CHECK_EQ(ret, 10, "written 10 bytes");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], ((i + 1) % 10) + ASCII_A, "Check data");
-
- // let tail > head
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 9);
- rbuf_bump_tail_noopt(buff, 9);
- rbuf_bump_head(buff, 1);
- ret = rbuf_push(buff, test_data, 9);
- CHECK_EQ(ret, 9, "written 9 bytes");
- CHECK_EQ(buff->head, buff->end - 1, "head_ptr");
- CHECK_EQ(buff->tail, buff->head, "tail_ptr");
- rbuf_bump_tail(buff, 1);
- //TODO push byte can be usefull optimisation
- ret = rbuf_push(buff, &test_data[9], 1);
- CHECK_EQ(ret, 1, "written 1 byte");
- CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], i + ASCII_A, "Check data");
-
- subtest_no++;
- rbuf_flush(buff);
- rbuf_bump_head(buff, 9);
- rbuf_bump_tail_noopt(buff, 7);
- rbuf_bump_head(buff, 1);
- ret = rbuf_push(buff, test_data, 7);
- CHECK_EQ(ret, 7, "written 7 bytes");
- CHECK_EQ(buff->head, buff->data + 7, "head_ptr");
- CHECK_EQ(buff->tail, buff->head, "tail_ptr");
- rbuf_bump_tail(buff, 3);
- CHECK_EQ(buff->tail, buff->data, "tail_ptr");
- //TODO push byte can be usefull optimisation
- ret = rbuf_push(buff, &test_data[7], 3);
- CHECK_EQ(ret, 3, "written 3 bytes");
- CHECK_EQ(rbuf_bytes_free(buff), 0, "empty size == 0");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], i + ASCII_A, "Check data");
-
- // test can't overfill the buffer
- subtest_no++;
- rbuf_flush(buff);
- rbuf_push(buff, test_data, TEST_DATA_SIZE);
- CHECK_EQ(ret, 3, "written 10 bytes");
- for (i = 0; i < 10; i++)
- CHECK_EQ(buff->data[i], i + ASCII_A, "Check data");
-}
-
-#define TEST_RBUF_FIND_BYTES_SIZE 10
-void test_rbuf_find_bytes()
-{
- TEST_DECL();
- rbuf_t buff = rbuf_create(TEST_RBUF_FIND_BYTES_SIZE);
- char *filler_3 = " ";
- char *needle = "needle";
- int idx;
- char *ptr;
-
- // make sure needle is wrapped aroung in the buffer
- // to test we still can find it
- // target "edle ne"
- rbuf_bump_head(buff, TEST_RBUF_FIND_BYTES_SIZE / 2);
- rbuf_push(buff, filler_3, strlen(filler_3));
- rbuf_bump_tail(buff, TEST_RBUF_FIND_BYTES_SIZE / 2);
- rbuf_push(buff, needle, strlen(needle));
- ptr = rbuf_find_bytes(buff, needle, strlen(needle), &idx);
- CHECK_EQ(ptr, buff->data + (TEST_RBUF_FIND_BYTES_SIZE / 2) + strlen(filler_3), "Pointer to needle correct");
- CHECK_EQ(idx, ptr - buff->tail, "Check needle index");
-}
-
-int main()
-{
- test_rbuf_bump_head();
- test_rbuf_bump_tail();
- test_rbuf_get_linear_insert_range();
- test_rbuf_push();
- test_rbuf_find_bytes();
-
- printf(
- KNRM "Total Tests %d, Total Checks %d, Successful Checks %d, Failed Checks %d\n",
- total_tests, total_checks, total_checks - total_fails, total_fails);
- if (total_fails)
- printf(KRED "!!!Some test(s) Failed!!!\n");
- else
- printf(KGRN "ALL TESTS PASSED\n");
-
- return total_fails;
-}
diff --git a/src/aclk/mqtt_websockets/c_rhash/c_rhash.c b/src/aclk/mqtt_websockets/c_rhash/c_rhash.c
deleted file mode 100644
index a71b500e2..000000000
--- a/src/aclk/mqtt_websockets/c_rhash/c_rhash.c
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include "c_rhash_internal.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef DEBUG_VERBOSE
-#include <stdio.h>
-#endif
-
-#define c_rmalloc(...) malloc(__VA_ARGS__)
-#define c_rcalloc(...) calloc(__VA_ARGS__)
-#define c_rfree(...) free(__VA_ARGS__)
-
-static inline uint32_t simple_hash(const char *name) {
- unsigned char *s = (unsigned char *) name;
- uint32_t hval = 0x811c9dc5;
- while (*s) {
- hval *= 16777619;
- hval ^= (uint32_t) *s++;
- }
- return hval;
-}
-
-c_rhash c_rhash_new(size_t bin_count) {
- if (!bin_count)
- bin_count = 1000;
-
- c_rhash hash = c_rcalloc(1, sizeof(struct c_rhash_s) + (bin_count * sizeof(struct bin_ll*)) );
- if (hash == NULL)
- return NULL;
-
- hash->bin_count = bin_count;
- hash->bins = (c_rhash_bin *)((char*)hash + sizeof(struct c_rhash_s));
-
- return hash;
-}
-
-static size_t get_itemtype_len(uint8_t item_type, const void* item_data) {
- switch (item_type) {
- case ITEMTYPE_STRING:
- return strlen(item_data) + 1;
- case ITEMTYPE_UINT64:
- return sizeof(uint64_t);
- case ITEMTYPE_UINT8:
- return 1;
- case ITEMTYPE_OPAQUE_PTR:
- return sizeof(void*);
- default:
- return 0;
- }
-}
-
-static int compare_bin_item(struct bin_item *item, uint8_t key_type, const void *key) {
- if (item->key_type != key_type)
- return 1;
-
- size_t key_value_len = get_itemtype_len(key_type, key);
-
- if(key_type == ITEMTYPE_STRING) {
- size_t new_key_value_len = get_itemtype_len(item->key_type, item->key);
- if (new_key_value_len != key_value_len)
- return 1;
- }
-
- if(memcmp(item->key, key, key_value_len) == 0) {
- return 0;
- }
-
- return 1;
-}
-
-static int insert_into_bin(c_rhash_bin *bin, uint8_t key_type, const void *key, uint8_t value_type, const void *value) {
- struct bin_item *prev = NULL;
- while (*bin != NULL) {
- if (!compare_bin_item(*bin, key_type, key)) {
-#ifdef DEBUG_VERBOSE
- printf("Key already present! Updating value!\n");
-#endif
-// TODO: optimize here if the new value is of different kind compared to the old one
-// in case it is not crazily bigger we can reuse the memory and avoid malloc and free
- c_rfree((*bin)->value);
- (*bin)->value_type = value_type;
- (*bin)->value = c_rmalloc(get_itemtype_len(value_type, value));
- if ((*bin)->value == NULL)
- return 1;
- memcpy((*bin)->value, value, get_itemtype_len(value_type, value));
- return 0;
- }
- prev = *bin;
- bin = &(*bin)->next;
- }
-
- if (*bin == NULL)
- *bin = c_rcalloc(1, sizeof(struct bin_item));
- if (prev != NULL)
- prev->next = *bin;
-
- (*bin)->key_type = key_type;
- size_t len = get_itemtype_len(key_type, key);
- (*bin)->key = c_rmalloc(len);
- memcpy((*bin)->key, key, len);
-
- (*bin)->value_type = value_type;
- len = get_itemtype_len(value_type, value);
- (*bin)->value = c_rmalloc(len);
- memcpy((*bin)->value, value, len);
- return 0;
-}
-
-static inline uint32_t get_bin_idx_str(c_rhash hash, const char *key) {
- uint32_t nhash = simple_hash(key);
- return nhash % hash->bin_count;
-}
-
-static inline c_rhash_bin *get_binptr_by_str(c_rhash hash, const char *key) {
- return &hash->bins[get_bin_idx_str(hash, key)];
-}
-
-int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value) {
- c_rhash_bin *bin = get_binptr_by_str(hash, key);
-
-#ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
-#endif
-
- return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_OPAQUE_PTR, &value);
-}
-
-int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value) {
- c_rhash_bin *bin = get_binptr_by_str(hash, key);
-
-#ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
-#endif
-
- return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_UINT8, &value);
-}
-
-int c_rhash_insert_uint64_ptr(c_rhash hash, uint64_t key, void *value) {
- c_rhash_bin *bin = &hash->bins[key % hash->bin_count];
-
-#ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
-#endif
-
- return insert_into_bin(bin, ITEMTYPE_UINT64, &key, ITEMTYPE_OPAQUE_PTR, &value);
-}
-
-int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val) {
- uint32_t nhash = get_bin_idx_str(hash, key);
-
- struct bin_item *bin = hash->bins[nhash];
-
- while (bin) {
- if (bin->key_type == ITEMTYPE_STRING) {
- if (!strcmp(bin->key, key)) {
- *ret_val = *(uint8_t*)bin->value;
- return 0;
- }
- }
- bin = bin->next;
- }
- return 1;
-}
-
-int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val) {
- uint32_t nhash = get_bin_idx_str(hash, key);
-
- struct bin_item *bin = hash->bins[nhash];
-
- while (bin) {
- if (bin->key_type == ITEMTYPE_STRING) {
- if (!strcmp(bin->key, key)) {
- *ret_val = *((void**)bin->value);
- return 0;
- }
- }
- bin = bin->next;
- }
- *ret_val = NULL;
- return 1;
-}
-
-int c_rhash_get_ptr_by_uint64(c_rhash hash, uint64_t key, void **ret_val) {
- uint32_t nhash = key % hash->bin_count;
-
- struct bin_item *bin = hash->bins[nhash];
-
- while (bin) {
- if (bin->key_type == ITEMTYPE_UINT64) {
- if (*((uint64_t *)bin->key) == key) {
- *ret_val = *((void**)bin->value);
- return 0;
- }
- }
- bin = bin->next;
- }
- *ret_val = NULL;
- return 1;
-}
-
-static void c_rhash_destroy_bin(c_rhash_bin bin) {
- struct bin_item *next;
- do {
- next = bin->next;
- c_rfree(bin->key);
- c_rfree(bin->value);
- c_rfree(bin);
- bin = next;
- } while (bin != NULL);
-}
-
-int c_rhash_iter_uint64_keys(c_rhash hash, c_rhash_iter_t *iter, uint64_t *key) {
- while (iter->bin < hash->bin_count) {
- if (iter->item != NULL)
- iter->item = iter->item->next;
- if (iter->item == NULL) {
- if (iter->initialized)
- iter->bin++;
- else
- iter->initialized = 1;
- if (iter->bin < hash->bin_count)
- iter->item = hash->bins[iter->bin];
- }
- if (iter->item != NULL && iter->item->key_type == ITEMTYPE_UINT64) {
- *key = *(uint64_t*)iter->item->key;
- return 0;
- }
- }
- return 1;
-}
-
-int c_rhash_iter_str_keys(c_rhash hash, c_rhash_iter_t *iter, const char **key) {
- while (iter->bin < hash->bin_count) {
- if (iter->item != NULL)
- iter->item = iter->item->next;
- if (iter->item == NULL) {
- if (iter->initialized)
- iter->bin++;
- else
- iter->initialized = 1;
- if (iter->bin < hash->bin_count)
- iter->item = hash->bins[iter->bin];
- }
- if (iter->item != NULL && iter->item->key_type == ITEMTYPE_STRING) {
- *key = (const char*)iter->item->key;
- return 0;
- }
- }
- return 1;
-}
-
-void c_rhash_destroy(c_rhash hash) {
- for (size_t i = 0; i < hash->bin_count; i++) {
- if (hash->bins[i] != NULL)
- c_rhash_destroy_bin(hash->bins[i]);
- }
- c_rfree(hash);
-}
diff --git a/src/aclk/mqtt_websockets/c_rhash/c_rhash.h b/src/aclk/mqtt_websockets/c_rhash/c_rhash.h
deleted file mode 100644
index 37addd161..000000000
--- a/src/aclk/mqtt_websockets/c_rhash/c_rhash.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stddef.h>
-
-#ifndef DEFAULT_BIN_COUNT
- #define DEFAULT_BIN_COUNT 1000
-#endif
-
-#define ITEMTYPE_UNSET (0x0)
-#define ITEMTYPE_STRING (0x1)
-#define ITEMTYPE_UINT8 (0x2)
-#define ITEMTYPE_UINT64 (0x3)
-#define ITEMTYPE_OPAQUE_PTR (0x4)
-
-typedef struct c_rhash_s *c_rhash;
-
-c_rhash c_rhash_new(size_t bin_count);
-
-void c_rhash_destroy(c_rhash hash);
-
-// # Insert
-// ## Insert where key is string
-int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value);
-int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value);
-// ## Insert where key is uint64
-int c_rhash_insert_uint64_ptr(c_rhash hash, uint64_t key, void *value);
-
-// # Get
-// ## Get where key is string
-int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val);
-int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val);
-// ## Get where key is uint64
-int c_rhash_get_ptr_by_uint64(c_rhash hash, uint64_t key, void **ret_val);
-
-typedef struct {
- size_t bin;
- struct bin_item *item;
- int initialized;
-} c_rhash_iter_t;
-
-#define C_RHASH_ITER_T_INITIALIZER { .bin = 0, .item = NULL, .initialized = 0 }
-
-#define c_rhash_iter_t_initialize(p_iter) memset(p_iter, 0, sizeof(c_rhash_iter_t))
-
-/*
- * goes trough whole hash map and returns every
- * type uint64 key present/stored
- *
- * it is not necessary to finish iterating and iterator can be reinitialized
- * there are no guarantees on the order in which the keys will come
- * behavior here is implementation dependent and can change any time
- *
- * returns:
- * 0 for every key and stores the key in *key
- * 1 on error or when all keys of this type has been already iterated over
- */
-int c_rhash_iter_uint64_keys(c_rhash hash, c_rhash_iter_t *iter, uint64_t *key);
-
-int c_rhash_iter_str_keys(c_rhash hash, c_rhash_iter_t *iter, const char **key);
diff --git a/src/aclk/mqtt_websockets/c_rhash/c_rhash_internal.h b/src/aclk/mqtt_websockets/c_rhash/c_rhash_internal.h
deleted file mode 100644
index 20f741076..000000000
--- a/src/aclk/mqtt_websockets/c_rhash/c_rhash_internal.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include "c_rhash.h"
-
-struct bin_item {
- uint8_t key_type:4;
- void *key;
- uint8_t value_type:4;
- void *value;
-
- struct bin_item *next;
-};
-
-typedef struct bin_item *c_rhash_bin;
-
-struct c_rhash_s {
- size_t bin_count;
- c_rhash_bin *bins;
-};
diff --git a/src/aclk/mqtt_websockets/c_rhash/tests.c b/src/aclk/mqtt_websockets/c_rhash/tests.c
deleted file mode 100644
index 909c5562d..000000000
--- a/src/aclk/mqtt_websockets/c_rhash/tests.c
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include <stdio.h>
-#include <string.h>
-
-#include "c_rhash.h"
-
-// terminal color codes
-#define KNRM "\x1B[0m"
-#define KRED "\x1B[31m"
-#define KGRN "\x1B[32m"
-#define KYEL "\x1B[33m"
-#define KBLU "\x1B[34m"
-#define KMAG "\x1B[35m"
-#define KCYN "\x1B[36m"
-#define KWHT "\x1B[37m"
-
-#define KEY_1 "key1"
-#define KEY_2 "keya"
-
-#define PRINT_ERR(str, ...) fprintf(stderr, "└─╼ ❌ " KRED str KNRM "\n" __VA_OPT__(,) __VA_ARGS__)
-
-#define ASSERT_RETVAL(fnc, comparator, expected_retval, ...) \
-{ int rval; \
-if(!((rval = fnc(__VA_ARGS__)) comparator expected_retval)) { \
- PRINT_ERR("Failed test. Value returned by \"%s\" in fnc:\"%s\",line:%d is not equal to expected value. Expected:%d, Got:%d", #fnc, __FUNCTION__, __LINE__, expected_retval, rval); \
- rc = 1; \
- goto test_cleanup; \
-} passed_subtest_count++;};
-
-#define ASSERT_VAL_UINT8(returned, expected) \
-if(returned != expected) { \
- PRINT_ERR("Failed test. Value returned (%d) doesn't match expected (%d)! fnc:\"%s\",line:%d", returned, expected, __FUNCTION__, __LINE__); \
- rc = 1; \
- goto test_cleanup; \
-} passed_subtest_count++;
-
-#define ASSERT_VAL_PTR(returned, expected) \
-if((void*)returned != (void*)expected) { \
- PRINT_ERR("Failed test. Value returned(%p) doesn't match expected(%p)! fnc:\"%s\",line:%d", (void*)returned, (void*)expected, __FUNCTION__, __LINE__); \
- rc = 1; \
- goto test_cleanup; \
-} passed_subtest_count++;
-
-#define ALL_SUBTESTS_PASS() printf("└─╼ ✅" KGRN " Test \"%s\" DONE. All of %zu subtests PASS. (line:%d)\n" KNRM, __FUNCTION__, passed_subtest_count, __LINE__);
-
-#define TEST_START() size_t passed_subtest_count = 0; int rc = 0; printf("╒═ Starting test \"%s\"\n", __FUNCTION__);
-
-int test_str_uint8() {
- c_rhash hash = c_rhash_new(100);
- uint8_t val;
-
- TEST_START();
- // function should fail on empty hash
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, !=, 0, hash, KEY_1, &val);
-
- ASSERT_RETVAL(c_rhash_insert_str_uint8, ==, 0, hash, KEY_1, 5);
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, ==, 0, hash, KEY_1, &val);
- ASSERT_VAL_UINT8(5, val);
-
- ASSERT_RETVAL(c_rhash_insert_str_uint8, ==, 0, hash, KEY_2, 8);
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, ==, 0, hash, KEY_1, &val);
- ASSERT_VAL_UINT8(5, val);
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, ==, 0, hash, KEY_2, &val);
- ASSERT_VAL_UINT8(8, val);
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, !=, 0, hash, "sndnskjdf", &val);
-
- // test update of key
- ASSERT_RETVAL(c_rhash_insert_str_uint8, ==, 0, hash, KEY_1, 100);
- ASSERT_RETVAL(c_rhash_get_uint8_by_str, ==, 0, hash, KEY_1, &val);
- ASSERT_VAL_UINT8(100, val);
-
- ALL_SUBTESTS_PASS();
-test_cleanup:
- c_rhash_destroy(hash);
- return rc;
-}
-
-int test_uint64_ptr() {
- c_rhash hash = c_rhash_new(100);
- void *val;
-
- TEST_START();
-
- // function should fail on empty hash
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, !=, 0, hash, 0, &val);
-
- ASSERT_RETVAL(c_rhash_insert_uint64_ptr, ==, 0, hash, 0, &hash);
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, ==, 0, hash, 0, &val);
- ASSERT_VAL_PTR(&hash, val);
-
- ASSERT_RETVAL(c_rhash_insert_uint64_ptr, ==, 0, hash, 1, &val);
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, ==, 0, hash, 0, &val);
- ASSERT_VAL_PTR(&hash, val);
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, ==, 0, hash, 1, &val);
- ASSERT_VAL_PTR(&val, val);
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, !=, 0, hash, 2, &val);
-
- ALL_SUBTESTS_PASS();
-test_cleanup:
- c_rhash_destroy(hash);
- return rc;
-}
-
-#define UINT64_PTR_INC_ITERATION_COUNT 5000
-int test_uint64_ptr_incremental() {
- c_rhash hash = c_rhash_new(100);
- void *val;
-
- TEST_START();
-
- char a = 0x20;
- char *ptr = &a;
- while(ptr < &a + UINT64_PTR_INC_ITERATION_COUNT) {
- ASSERT_RETVAL(c_rhash_insert_uint64_ptr, ==, 0, hash, (ptr-&a), ptr);
- ptr++;
- }
-
- ptr = &a;
- char *retptr;
- for(int i = 0; i < UINT64_PTR_INC_ITERATION_COUNT; i++) {
- ASSERT_RETVAL(c_rhash_get_ptr_by_uint64, ==, 0, hash, i, (void**)&retptr);
- ASSERT_VAL_PTR(retptr, (&a+i));
- }
-
- ALL_SUBTESTS_PASS();
-test_cleanup:
- c_rhash_destroy(hash);
- return rc;
-}
-
-struct test_string {
- const char *str;
- int counter;
-};
-
-struct test_string test_strings[] = {
- { .str = "Cillum reprehenderit eiusmod elit nisi aliquip esse exercitation commodo Lorem voluptate esse.", .counter = 0 },
- { .str = "Ullamco eiusmod tempor occaecat ad.", .counter = 0 },
- { .str = "Esse aliquip tempor sint tempor ullamco duis aute incididunt ad.", .counter = 0 },
- { .str = "Cillum Lorem labore cupidatat commodo proident adipisicing.", .counter = 0 },
- { .str = "Quis ad cillum officia exercitation.", .counter = 0 },
- { .str = "Ipsum enim dolor ullamco amet sint nisi ut occaecat sint non.", .counter = 0 },
- { .str = "Id duis officia ipsum cupidatat velit fugiat.", .counter = 0 },
- { .str = "Aliqua non occaecat voluptate reprehenderit reprehenderit veniam minim exercitation ea aliquip enim aliqua deserunt qui.", .counter = 0 },
- { .str = "Ullamco elit tempor laboris reprehenderit quis deserunt duis quis tempor reprehenderit magna dolore reprehenderit exercitation.", .counter = 0 },
- { .str = "Culpa do dolor quis incididunt et labore in ex.", .counter = 0 },
- { .str = "Aliquip velit cupidatat qui incididunt ipsum nostrud eiusmod ut proident nisi magna fugiat excepteur.", .counter = 0 },
- { .str = "Aliqua qui dolore tempor id proident ullamco sunt magna.", .counter = 0 },
- { .str = "Labore eiusmod ut fugiat dolore reprehenderit mollit magna.", .counter = 0 },
- { .str = "Veniam aliquip dolor excepteur minim nulla esse cupidatat esse.", .counter = 0 },
- { .str = "Do quis dolor irure nostrud occaecat aute proident anim.", .counter = 0 },
- { .str = "Enim veniam non nulla ad quis sit amet.", .counter = 0 },
- { .str = "Cillum reprehenderit do enim esse do ullamco consectetur ea.", .counter = 0 },
- { .str = "Sit et duis sint anim qui ad anim labore exercitation sunt cupidatat.", .counter = 0 },
- { .str = "Dolor officia adipisicing sint pariatur in dolor occaecat officia reprehenderit magna.", .counter = 0 },
- { .str = "Aliquip dolore qui occaecat eiusmod sunt incididunt reprehenderit minim et.", .counter = 0 },
- { .str = "Aute fugiat laboris cillum tempor consequat tempor do non laboris culpa officia nisi.", .counter = 0 },
- { .str = "Et excepteur do aliquip fugiat nisi velit tempor officia enim quis elit incididunt.", .counter = 0 },
- { .str = "Eu officia adipisicing incididunt occaecat officia cupidatat enim sit sit officia.", .counter = 0 },
- { .str = "Do amet cillum duis pariatur commodo nulla cillum magna nulla Lorem veniam cupidatat.", .counter = 0 },
- { .str = "Dolor adipisicing voluptate laboris occaecat culpa aliquip ipsum ut consequat aliqua aliquip commodo sunt velit.", .counter = 0 },
- { .str = "Nulla proident ipsum quis nulla.", .counter = 0 },
- { .str = "Laborum adipisicing nulla do aute aliqua est quis sint culpa pariatur laborum voluptate qui.", .counter = 0 },
- { .str = "Proident eiusmod sunt et nulla elit pariatur dolore irure ex voluptate excepteur adipisicing consectetur.", .counter = 0 },
- { .str = "Consequat ex voluptate officia excepteur aute deserunt proident commodo et.", .counter = 0 },
- { .str = "Velit sit cupidatat dolor dolore.", .counter = 0 },
- { .str = "Sunt enim do non anim nostrud exercitation ullamco ex proident commodo.", .counter = 0 },
- { .str = "Id ex officia cillum ad.", .counter = 0 },
- { .str = "Laboris in sunt eiusmod veniam laboris nostrud.", .counter = 0 },
- { .str = "Ex magna occaecat ea ea incididunt aliquip.", .counter = 0 },
- { .str = "Sunt eiusmod ex nostrud eu pariatur sit cupidatat ea adipisicing cillum culpa esse consequat aliquip.", .counter = 0 },
- { .str = "Excepteur commodo qui incididunt enim culpa sunt non excepteur Lorem adipisicing.", .counter = 0 },
- { .str = "Quis officia est ullamco reprehenderit incididunt occaecat pariatur ex reprehenderit nisi.", .counter = 0 },
- { .str = "Culpa irure proident proident et eiusmod irure aliqua ipsum cupidatat minim sit.", .counter = 0 },
- { .str = "Qui cupidatat aliquip est velit magna veniam.", .counter = 0 },
- { .str = "Pariatur ad ad mollit nostrud non irure minim veniam anim aliquip quis eu.", .counter = 0 },
- { .str = "Nisi ex minim eu adipisicing tempor Lorem nisi do ad exercitation est non eu.", .counter = 0 },
- { .str = "Cupidatat do mollit ad commodo cupidatat ut.", .counter = 0 },
- { .str = "Est non excepteur eiusmod nostrud et eu.", .counter = 0 },
- { .str = "Cupidatat mollit nisi magna officia ut elit eiusmod.", .counter = 0 },
- { .str = "Est aliqua consectetur laboris ex consequat est ut dolor.", .counter = 0 },
- { .str = "Duis eu laboris laborum ut id Lorem nostrud qui ad velit proident fugiat minim ullamco.", .counter = 0 },
- { .str = "Pariatur esse excepteur anim amet excepteur irure sint quis esse ex cupidatat ut.", .counter = 0 },
- { .str = "Esse reprehenderit amet qui excepteur aliquip amet.", .counter = 0 },
- { .str = "Ullamco laboris elit labore adipisicing aute nulla qui laborum tempor officia ut dolor aute.", .counter = 0 },
- { .str = "Commodo sunt cillum velit minim laborum Lorem aliqua tempor ad id eu.", .counter = 0 },
- { .str = NULL, .counter = 0 }
-};
-
-uint32_t test_strings_contain_element(const char *str) {
- struct test_string *str_desc = test_strings;
- while(str_desc->str) {
- if (!strcmp(str, str_desc->str))
- return str_desc - test_strings;
- str_desc++;
- }
- return -1;
-}
-
-#define TEST_INCREMENT_STR_KEYS_HASH_SIZE 20
-int test_increment_str_keys() {
- c_rhash hash;
- const char *key;
-
- TEST_START();
-
- hash = c_rhash_new(TEST_INCREMENT_STR_KEYS_HASH_SIZE); // less than element count of test_strings
-
- c_rhash_iter_t iter = C_RHASH_ITER_T_INITIALIZER;
-
- // check iter on empty hash
- ASSERT_RETVAL(c_rhash_iter_str_keys, !=, 0, hash, &iter, &key);
-
- int32_t element_count = 0;
- while (test_strings[element_count].str) {
- ASSERT_RETVAL(c_rhash_insert_str_ptr, ==, 0, hash, test_strings[element_count].str, NULL);
- test_strings[element_count].counter++; // we want to test we got each key exactly once
- element_count++;
- }
-
- if (element_count <= TEST_INCREMENT_STR_KEYS_HASH_SIZE * 2) {
- // verify we are actually test also iteration trough single bin (when 2 keys have same hash pointing them to same bin)
- PRINT_ERR("For this test to properly test all the hash size needs to be much smaller than all test key count.");
- rc = 1;
- goto test_cleanup;
- }
-
- // we insert another type of key as iterator should skip it
- // in case is another type
- ASSERT_RETVAL(c_rhash_insert_uint64_ptr, ==, 0, hash, 5, NULL);
-
- c_rhash_iter_t_initialize(&iter);
- while(!c_rhash_iter_str_keys(hash, &iter, &key)) {
- element_count--;
- int i;
- if ( (i = test_strings_contain_element(key)) < 0) {
- PRINT_ERR("Key \"%s\" is not present in test_strings array! (Fnc: %s, Line: %d)", key, __FUNCTION__, __LINE__);
- rc = 1;
- goto test_cleanup;
- }
- passed_subtest_count++;
-
- test_strings[i].counter--;
- }
- ASSERT_VAL_UINT8(element_count, 0); // we added also same non string keys
-
- // check each key was present exactly once
- struct test_string *str_desc = test_strings;
- while (str_desc->str) {
- ASSERT_VAL_UINT8(str_desc->counter, 0);
- str_desc++;
- }
-
- ALL_SUBTESTS_PASS();
-test_cleanup:
- c_rhash_destroy(hash);
- return rc;
-}
-
-#define RUN_TEST(fnc) \
-if(fnc()) \
- return 1;
-
-int main(int argc, char *argv[]) {
- RUN_TEST(test_str_uint8);
- RUN_TEST(test_uint64_ptr);
- RUN_TEST(test_uint64_ptr_incremental);
- RUN_TEST(test_increment_str_keys);
- // TODO hash with mixed key tests
- // TODO iterator test
- return 0;
-}
diff --git a/src/aclk/mqtt_websockets/common_internal.h b/src/aclk/mqtt_websockets/common_internal.h
index 2be1c45b8..d79dbb3f3 100644
--- a/src/aclk/mqtt_websockets/common_internal.h
+++ b/src/aclk/mqtt_websockets/common_internal.h
@@ -1,27 +1,12 @@
-// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef COMMON_INTERNAL_H
#define COMMON_INTERNAL_H
#include "endian_compat.h"
-#ifdef MQTT_WSS_CUSTOM_ALLOC
-#include "../helpers/mqtt_wss_pal.h"
-#else
-#define mw_malloc(...) malloc(__VA_ARGS__)
-#define mw_calloc(...) calloc(__VA_ARGS__)
-#define mw_free(...) free(__VA_ARGS__)
-#define mw_strdup(...) strdup(__VA_ARGS__)
-#define mw_realloc(...) realloc(__VA_ARGS__)
-#endif
-
#ifndef MQTT_WSS_FRAG_MEMALIGN
#define MQTT_WSS_FRAG_MEMALIGN (8)
#endif
-#define OPENSSL_VERSION_095 0x00905100L
-#define OPENSSL_VERSION_097 0x00907000L
-#define OPENSSL_VERSION_110 0x10100000L
-#define OPENSSL_VERSION_111 0x10101000L
-
#endif /* COMMON_INTERNAL_H */
diff --git a/src/aclk/mqtt_websockets/common_public.h b/src/aclk/mqtt_websockets/common_public.h
index a855737f9..8f3b4f7d1 100644
--- a/src/aclk/mqtt_websockets/common_public.h
+++ b/src/aclk/mqtt_websockets/common_public.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#ifndef MQTT_WEBSOCKETS_COMMON_PUBLIC_H
#define MQTT_WEBSOCKETS_COMMON_PUBLIC_H
diff --git a/src/aclk/mqtt_websockets/mqtt_ng.c b/src/aclk/mqtt_websockets/mqtt_ng.c
index 8ad6bd5c9..9abe77b5f 100644
--- a/src/aclk/mqtt_websockets/mqtt_ng.c
+++ b/src/aclk/mqtt_websockets/mqtt_ng.c
@@ -1,35 +1,19 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
+// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <inttypes.h>
-
-#include "c_rhash/c_rhash.h"
+#include "libnetdata/libnetdata.h"
#include "common_internal.h"
#include "mqtt_constants.h"
-#include "mqtt_wss_log.h"
#include "mqtt_ng.h"
-#define UNIT_LOG_PREFIX "mqtt_client: "
-#define FATAL(fmt, ...) mws_fatal(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define ERROR(fmt, ...) mws_error(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define WARN(fmt, ...) mws_warn (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define INFO(fmt, ...) mws_info (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define DEBUG(fmt, ...) mws_debug(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-
#define SMALL_STRING_DONT_FRAGMENT_LIMIT 128
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
-#define LOCK_HDR_BUFFER(buffer) pthread_mutex_lock(&((buffer)->mutex))
-#define UNLOCK_HDR_BUFFER(buffer) pthread_mutex_unlock(&((buffer)->mutex))
+#define LOCK_HDR_BUFFER(buffer) spinlock_lock(&((buffer)->spinlock))
+#define UNLOCK_HDR_BUFFER(buffer) spinlock_unlock(&((buffer)->spinlock))
#define BUFFER_FRAG_GARBAGE_COLLECT 0x01
// some packets can be marked for garbage collection
@@ -75,17 +59,17 @@ struct transaction_buffer {
// to be able to revert state easily
// in case of error mid processing
struct header_buffer state_backup;
- pthread_mutex_t mutex;
+ SPINLOCK spinlock;
struct buffer_fragment *sending_frag;
};
enum mqtt_client_state {
- RAW = 0,
- CONNECT_PENDING,
- CONNECTING,
- CONNECTED,
- ERROR,
- DISCONNECTED
+ MQTT_STATE_RAW = 0,
+ MQTT_STATE_CONNECT_PENDING,
+ MQTT_STATE_CONNECTING,
+ MQTT_STATE_CONNECTED,
+ MQTT_STATE_ERROR,
+ MQTT_STATE_DISCONNECTED
};
enum parser_state {
@@ -224,7 +208,7 @@ struct topic_aliases_data {
c_rhash stoi_dict;
uint32_t idx_max;
uint32_t idx_assigned;
- pthread_rwlock_t rwlock;
+ SPINLOCK spinlock;
};
struct mqtt_ng_client {
@@ -234,8 +218,6 @@ struct mqtt_ng_client {
mqtt_msg_data connect_msg;
- mqtt_wss_log_ctx_t log;
-
mqtt_ng_send_fnc_t send_fnc_ptr;
void *user_ctx;
@@ -253,7 +235,7 @@ struct mqtt_ng_client {
unsigned int ping_pending:1;
struct mqtt_ng_stats stats;
- pthread_mutex_t stats_mutex;
+ SPINLOCK stats_spinlock;
struct topic_aliases_data tx_topic_aliases;
c_rhash rx_aliases;
@@ -407,7 +389,7 @@ enum memory_mode {
CALLER_RESPONSIBLE
};
-static inline enum memory_mode ptr2memory_mode(void * ptr) {
+static enum memory_mode ptr2memory_mode(void * ptr) {
if (ptr == NULL)
return MEMCPY;
if (ptr == CALLER_RESPONSIBILITY)
@@ -492,15 +474,8 @@ static void buffer_rebuild(struct header_buffer *buf)
} while(frag);
}
-static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx)
+static void buffer_garbage_collect(struct header_buffer *buf)
{
-#if !defined(MQTT_DEBUG_VERBOSE) && !defined(ADDITIONAL_CHECKS)
- (void) log_ctx;
-#endif
-#ifdef MQTT_DEBUG_VERBOSE
- mws_debug(log_ctx, "Buffer Garbage Collection!");
-#endif
-
struct buffer_fragment *frag = BUFFER_FIRST_FRAG(buf);
while (frag) {
if (!frag_is_marked_for_gc(frag))
@@ -511,12 +486,8 @@ static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t
frag = frag->next;
}
- if (frag == BUFFER_FIRST_FRAG(buf)) {
-#ifdef MQTT_DEBUG_VERBOSE
- mws_debug(log_ctx, "Buffer Garbage Collection! No Space Reclaimed!");
-#endif
+ if (frag == BUFFER_FIRST_FRAG(buf))
return;
- }
if (!frag) {
buf->tail_frag = NULL;
@@ -535,21 +506,17 @@ static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t
buffer_rebuild(buf);
}
-static void transaction_buffer_garbage_collect(struct transaction_buffer *buf, mqtt_wss_log_ctx_t log_ctx)
+static void transaction_buffer_garbage_collect(struct transaction_buffer *buf)
{
-#ifdef MQTT_DEBUG_VERBOSE
- mws_debug(log_ctx, "Transaction Buffer Garbage Collection! %s", buf->sending_frag == NULL ? "NULL" : "in flight message");
-#endif
-
// Invalidate the cached sending fragment
// as we will move data around
if (buf->sending_frag != &ping_frag)
buf->sending_frag = NULL;
- buffer_garbage_collect(&buf->hdr_buffer, log_ctx);
+ buffer_garbage_collect(&buf->hdr_buffer);
}
-static int transaction_buffer_grow(struct transaction_buffer *buf, mqtt_wss_log_ctx_t log_ctx, float rate, size_t max)
+static int transaction_buffer_grow(struct transaction_buffer *buf, float rate, size_t max)
{
if (buf->hdr_buffer.size >= max)
return 0;
@@ -565,35 +532,30 @@ static int transaction_buffer_grow(struct transaction_buffer *buf, mqtt_wss_log_
void *ret = reallocz(buf->hdr_buffer.data, buf->hdr_buffer.size);
if (ret == NULL) {
- mws_warn(log_ctx, "Buffer growth failed (realloc)");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "Buffer growth failed (realloc)");
return 1;
}
- mws_debug(log_ctx, "Message metadata buffer was grown");
+ nd_log(NDLS_DAEMON, NDLP_DEBUG, "Message metadata buffer was grown");
buf->hdr_buffer.data = ret;
buffer_rebuild(&buf->hdr_buffer);
return 0;
}
-inline static int transaction_buffer_init(struct transaction_buffer *to_init, size_t size)
+inline static void transaction_buffer_init(struct transaction_buffer *to_init, size_t size)
{
- pthread_mutex_init(&to_init->mutex, NULL);
+ spinlock_init(&to_init->spinlock);
to_init->hdr_buffer.size = size;
to_init->hdr_buffer.data = mallocz(size);
- if (to_init->hdr_buffer.data == NULL)
- return 1;
-
to_init->hdr_buffer.tail = to_init->hdr_buffer.data;
to_init->hdr_buffer.tail_frag = NULL;
- return 0;
}
static void transaction_buffer_destroy(struct transaction_buffer *to_init)
{
buffer_purge(&to_init->hdr_buffer);
- pthread_mutex_destroy(&to_init->mutex);
freez(to_init->hdr_buffer.data);
}
@@ -629,54 +591,30 @@ void transaction_buffer_transaction_rollback(struct transaction_buffer *buf, str
struct mqtt_ng_client *mqtt_ng_init(struct mqtt_ng_init *settings)
{
struct mqtt_ng_client *client = callocz(1, sizeof(struct mqtt_ng_client));
- if (client == NULL)
- return NULL;
- if (transaction_buffer_init(&client->main_buffer, HEADER_BUFFER_SIZE))
- goto err_free_client;
+ transaction_buffer_init(&client->main_buffer, HEADER_BUFFER_SIZE);
client->rx_aliases = RX_ALIASES_INITIALIZE();
- if (client->rx_aliases == NULL)
- goto err_free_trx_buf;
- if (pthread_mutex_init(&client->stats_mutex, NULL))
- goto err_free_rx_alias;
+ spinlock_init(&client->stats_spinlock);
+ spinlock_init(&client->tx_topic_aliases.spinlock);
client->tx_topic_aliases.stoi_dict = TX_ALIASES_INITIALIZE();
- if (client->tx_topic_aliases.stoi_dict == NULL)
- goto err_free_stats_mutex;
client->tx_topic_aliases.idx_max = UINT16_MAX;
- if (pthread_rwlock_init(&client->tx_topic_aliases.rwlock, NULL))
- goto err_free_tx_alias;
-
// TODO just embed the struct into mqtt_ng_client
client->parser.received_data = settings->data_in;
client->send_fnc_ptr = settings->data_out_fnc;
client->user_ctx = settings->user_ctx;
- client->log = settings->log;
-
client->puback_callback = settings->puback_callback;
client->connack_callback = settings->connack_callback;
client->msg_callback = settings->msg_callback;
return client;
-
-err_free_tx_alias:
- c_rhash_destroy(client->tx_topic_aliases.stoi_dict);
-err_free_stats_mutex:
- pthread_mutex_destroy(&client->stats_mutex);
-err_free_rx_alias:
- c_rhash_destroy(client->rx_aliases);
-err_free_trx_buf:
- transaction_buffer_destroy(&client->main_buffer);
-err_free_client:
- freez(client);
- return NULL;
}
-static inline uint8_t get_control_packet_type(uint8_t first_hdr_byte)
+static uint8_t get_control_packet_type(uint8_t first_hdr_byte)
{
return first_hdr_byte >> 4;
}
@@ -708,33 +646,27 @@ static void mqtt_ng_destroy_tx_alias_hash(c_rhash hash)
void mqtt_ng_destroy(struct mqtt_ng_client *client)
{
transaction_buffer_destroy(&client->main_buffer);
- pthread_mutex_destroy(&client->stats_mutex);
mqtt_ng_destroy_tx_alias_hash(client->tx_topic_aliases.stoi_dict);
- pthread_rwlock_destroy(&client->tx_topic_aliases.rwlock);
mqtt_ng_destroy_rx_alias_hash(client->rx_aliases);
freez(client);
}
-int frag_set_external_data(mqtt_wss_log_ctx_t log, struct buffer_fragment *frag, void *data, size_t data_len, free_fnc_t data_free_fnc)
+int frag_set_external_data(struct buffer_fragment *frag, void *data, size_t data_len, free_fnc_t data_free_fnc)
{
if (frag->len) {
// TODO?: This could potentially be done in future if we set rule
// external data always follows in buffer data
// could help reduce fragmentation in some messages but
// currently not worth it considering time is tight
- mws_fatal(log, UNIT_LOG_PREFIX "INTERNAL ERROR: Cannot set external data to fragment already containing in buffer data!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "INTERNAL ERROR: Cannot set external data to fragment already containing in buffer data!");
return 1;
}
switch (ptr2memory_mode(data_free_fnc)) {
case MEMCPY:
frag->data = mallocz(data_len);
- if (frag->data == NULL) {
- mws_error(log, UNIT_LOG_PREFIX "OOM while malloc @_optimized_add");
- return 1;
- }
memcpy(frag->data, data, data_len);
break;
case EXTERNAL_FREE_AFTER_USE:
@@ -816,18 +748,18 @@ static size_t mqtt_ng_connect_size(struct mqtt_auth_properties *auth,
#define PACK_2B_INT(buffer, integer, frag) { *(uint16_t *)WRITE_POS(frag) = htobe16((integer)); \
DATA_ADVANCE(buffer, sizeof(uint16_t), frag); }
-static int _optimized_add(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx, void *data, size_t data_len, free_fnc_t data_free_fnc, struct buffer_fragment **frag)
+static int _optimized_add(struct header_buffer *buf, void *data, size_t data_len, free_fnc_t data_free_fnc, struct buffer_fragment **frag)
{
if (data_len > SMALL_STRING_DONT_FRAGMENT_LIMIT) {
buffer_frag_flag_t flags = BUFFER_FRAG_DATA_EXTERNAL;
if ((*frag)->flags & BUFFER_FRAG_GARBAGE_COLLECT_ON_SEND)
flags |= BUFFER_FRAG_GARBAGE_COLLECT_ON_SEND;
if( (*frag = buffer_new_frag(buf, flags)) == NULL ) {
- mws_error(log_ctx, "Out of buffer space while generating the message");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Out of buffer space while generating the message");
return 1;
}
- if (frag_set_external_data(log_ctx, *frag, data, data_len, data_free_fnc)) {
- mws_error(log_ctx, "Error adding external data to newly created fragment");
+ if (frag_set_external_data(*frag, data, data_len, data_free_fnc)) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error adding external data to newly created fragment");
return 1;
}
// we dont want to write to this fragment anymore
@@ -842,31 +774,30 @@ static int _optimized_add(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx,
return 0;
}
-#define TRY_GENERATE_MESSAGE(generator_function, client, ...) \
- int rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
+#define TRY_GENERATE_MESSAGE(generator_function, ...) \
+ int rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
if (rc == MQTT_NG_MSGGEN_BUFFER_OOM) { \
LOCK_HDR_BUFFER(&client->main_buffer); \
- transaction_buffer_garbage_collect((&client->main_buffer), client->log); \
+ transaction_buffer_garbage_collect((&client->main_buffer)); \
UNLOCK_HDR_BUFFER(&client->main_buffer); \
- rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
+ rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
if (rc == MQTT_NG_MSGGEN_BUFFER_OOM && client->max_mem_bytes) { \
LOCK_HDR_BUFFER(&client->main_buffer); \
- transaction_buffer_grow((&client->main_buffer), client->log, GROWTH_FACTOR, client->max_mem_bytes); \
+ transaction_buffer_grow((&client->main_buffer),GROWTH_FACTOR, client->max_mem_bytes); \
UNLOCK_HDR_BUFFER(&client->main_buffer); \
- rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
+ rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
} \
if (rc == MQTT_NG_MSGGEN_BUFFER_OOM) \
- mws_error(client->log, "%s failed to generate message due to insufficient buffer space (line %d)", __FUNCTION__, __LINE__); \
+ nd_log(NDLS_DAEMON, NDLP_ERR, "%s failed to generate message due to insufficient buffer space (line %d)", __FUNCTION__, __LINE__); \
} \
if (rc == MQTT_NG_MSGGEN_OK) { \
- pthread_mutex_lock(&client->stats_mutex); \
+ spinlock_lock(&client->stats_spinlock); \
client->stats.tx_messages_queued++; \
- pthread_mutex_unlock(&client->stats_mutex); \
+ spinlock_unlock(&client->stats_spinlock); \
} \
return rc;
mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
- mqtt_wss_log_ctx_t log_ctx,
struct mqtt_auth_properties *auth,
struct mqtt_lwt_properties *lwt,
uint8_t clean_start,
@@ -874,7 +805,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
{
// Sanity Checks First (are given parameters correct and up to MQTT spec)
if (!auth->client_id) {
- mws_error(log_ctx, "ClientID must be set. [MQTT-3.1.3-3]");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "ClientID must be set. [MQTT-3.1.3-3]");
return NULL;
}
@@ -885,29 +816,29 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
// however server MUST allow ClientIDs between 1-23 bytes [MQTT-3.1.3-5]
// so we will warn client server might not like this and he is using it
// at his own risk!
- mws_warn(log_ctx, "client_id provided is empty string. This might not be allowed by server [MQTT-3.1.3-6]");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "client_id provided is empty string. This might not be allowed by server [MQTT-3.1.3-6]");
}
if(len > MQTT_MAX_CLIENT_ID) {
// [MQTT-3.1.3-5] server MUST allow client_id length 1-32
// server MAY allow longer client_id, if user provides longer client_id
// warn them he is doing so at his own risk!
- mws_warn(log_ctx, "client_id provided is longer than 23 bytes, server might not allow that [MQTT-3.1.3-5]");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "client_id provided is longer than 23 bytes, server might not allow that [MQTT-3.1.3-5]");
}
if (lwt) {
if (lwt->will_message && lwt->will_message_size > 65535) {
- mws_error(log_ctx, "Will message cannot be longer than 65535 bytes due to MQTT protocol limitations [MQTT-3.1.3-4] and [MQTT-1.5.6]");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Will message cannot be longer than 65535 bytes due to MQTT protocol limitations [MQTT-3.1.3-4] and [MQTT-1.5.6]");
return NULL;
}
if (!lwt->will_topic) { //TODO topic given with strlen==0 ? check specs
- mws_error(log_ctx, "If will message is given will topic must also be given [MQTT-3.1.3.3]");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "If will message is given will topic must also be given [MQTT-3.1.3.3]");
return NULL;
}
if (lwt->will_qos > MQTT_MAX_QOS) {
// refer to [MQTT-3-1.2-12]
- mws_error(log_ctx, "QOS for LWT message is bigger than max");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "QOS for LWT message is bigger than max");
return NULL;
}
}
@@ -941,8 +872,10 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
*connect_flags = 0;
if (auth->username)
*connect_flags |= MQTT_CONNECT_FLAG_USERNAME;
+
if (auth->password)
*connect_flags |= MQTT_CONNECT_FLAG_PASSWORD;
+
if (lwt) {
*connect_flags |= MQTT_CONNECT_FLAG_LWT;
*connect_flags |= lwt->will_qos << MQTT_CONNECT_FLAG_QOS_BITSHIFT;
@@ -966,7 +899,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
// [MQTT-3.1.3.1] Client identifier
CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->client_id), frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->client_id, strlen(auth->client_id), auth->client_id_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, auth->client_id, strlen(auth->client_id), auth->client_id_free, &frag))
goto fail_rollback;
if (lwt != NULL) {
@@ -980,7 +913,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
// Will Topic [MQTT-3.1.3.3]
CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, strlen(lwt->will_topic), frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, lwt->will_topic, strlen(lwt->will_topic), lwt->will_topic_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, lwt->will_topic, strlen(lwt->will_topic), lwt->will_topic_free, &frag))
goto fail_rollback;
// Will Payload [MQTT-3.1.3.4]
@@ -988,7 +921,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, lwt->will_message_size, frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, lwt->will_message, lwt->will_message_size, lwt->will_topic_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, lwt->will_message, lwt->will_message_size, lwt->will_topic_free, &frag))
goto fail_rollback;
}
}
@@ -998,7 +931,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->username), frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->username, strlen(auth->username), auth->username_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, auth->username, strlen(auth->username), auth->username_free, &frag))
goto fail_rollback;
}
@@ -1007,7 +940,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->password), frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->password, strlen(auth->password), auth->password_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, auth->password, strlen(auth->password), auth->password_free, &frag))
goto fail_rollback;
}
trx_buf->hdr_buffer.tail_frag->flags |= BUFFER_FRAG_MQTT_PACKET_TAIL;
@@ -1024,7 +957,7 @@ int mqtt_ng_connect(struct mqtt_ng_client *client,
uint8_t clean_start,
uint16_t keep_alive)
{
- client->client_state = RAW;
+ client->client_state = MQTT_STATE_RAW;
client->parser.state = MQTT_PARSE_FIXED_HEADER_PACKET_TYPE;
LOCK_HDR_BUFFER(&client->main_buffer);
@@ -1033,28 +966,23 @@ int mqtt_ng_connect(struct mqtt_ng_client *client,
buffer_purge(&client->main_buffer.hdr_buffer);
UNLOCK_HDR_BUFFER(&client->main_buffer);
- pthread_rwlock_wrlock(&client->tx_topic_aliases.rwlock);
+ spinlock_lock(&client->tx_topic_aliases.spinlock);
// according to MQTT spec topic aliases should not be persisted
// even if clean session is true
mqtt_ng_destroy_tx_alias_hash(client->tx_topic_aliases.stoi_dict);
+
client->tx_topic_aliases.stoi_dict = TX_ALIASES_INITIALIZE();
- if (client->tx_topic_aliases.stoi_dict == NULL) {
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
- return 1;
- }
client->tx_topic_aliases.idx_assigned = 0;
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
+ spinlock_unlock(&client->tx_topic_aliases.spinlock);
mqtt_ng_destroy_rx_alias_hash(client->rx_aliases);
client->rx_aliases = RX_ALIASES_INITIALIZE();
- if (client->rx_aliases == NULL)
- return 1;
- client->connect_msg = mqtt_ng_generate_connect(&client->main_buffer, client->log, auth, lwt, clean_start, keep_alive);
+ client->connect_msg = mqtt_ng_generate_connect(&client->main_buffer, auth, lwt, clean_start, keep_alive);
if (client->connect_msg == NULL)
return 1;
- pthread_mutex_lock(&client->stats_mutex);
+ spinlock_lock(&client->stats_spinlock);
if (clean_start)
client->stats.tx_messages_queued = 1;
else
@@ -1062,9 +990,9 @@ int mqtt_ng_connect(struct mqtt_ng_client *client,
client->stats.tx_messages_sent = 0;
client->stats.rx_messages_rcvd = 0;
- pthread_mutex_unlock(&client->stats_mutex);
+ spinlock_unlock(&client->stats_spinlock);
- client->client_state = CONNECT_PENDING;
+ client->client_state = MQTT_STATE_CONNECT_PENDING;
return 0;
}
@@ -1074,15 +1002,16 @@ uint16_t get_unused_packet_id() {
return packet_id ? packet_id : ++packet_id;
}
-static inline size_t mqtt_ng_publish_size(const char *topic,
- size_t msg_len,
- uint16_t topic_id)
+static size_t mqtt_ng_publish_size(
+ const char *topic,
+ size_t msg_len,
+ uint16_t topic_id)
{
- size_t retval = 2 /* Topic Name Length */
- + (topic == NULL ? 0 : strlen(topic))
- + 2 /* Packet identifier */
- + 1 /* Properties Length TODO for now fixed to 1 property */
- + msg_len;
+ size_t retval = 2
+ + (topic == NULL ? 0 : strlen(topic)) /* Topic Name Length */
+ + 2 /* Packet identifier */
+ + 1 /* Properties Length for now fixed to 1 property */
+ + msg_len;
if (topic_id)
retval += 3;
@@ -1091,7 +1020,6 @@ static inline size_t mqtt_ng_publish_size(const char *topic,
}
int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
- mqtt_wss_log_ctx_t log_ctx,
char *topic,
free_fnc_t topic_free,
void *msg,
@@ -1130,7 +1058,7 @@ int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
// [MQTT-3.3.2.1]
PACK_2B_INT(&trx_buf->hdr_buffer, topic == NULL ? 0 : strlen(topic), frag);
if (topic != NULL) {
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, topic, strlen(topic), topic_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, topic, strlen(topic), topic_free, &frag))
goto fail_rollback;
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
}
@@ -1154,7 +1082,7 @@ int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
if( (frag = buffer_new_frag(&trx_buf->hdr_buffer, BUFFER_FRAG_DATA_EXTERNAL)) == NULL )
goto fail_rollback;
- if (frag_set_external_data(log_ctx, frag, msg, msg_len, msg_free))
+ if (frag_set_external_data(frag, msg, msg_len, msg_free))
goto fail_rollback;
trx_buf->hdr_buffer.tail_frag->flags |= BUFFER_FRAG_MQTT_PACKET_TAIL;
@@ -1178,9 +1106,9 @@ int mqtt_ng_publish(struct mqtt_ng_client *client,
uint16_t *packet_id)
{
struct topic_alias_data *alias = NULL;
- pthread_rwlock_rdlock(&client->tx_topic_aliases.rwlock);
+ spinlock_lock(&client->tx_topic_aliases.spinlock);
c_rhash_get_ptr_by_str(client->tx_topic_aliases.stoi_dict, topic, (void**)&alias);
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
+ spinlock_unlock(&client->tx_topic_aliases.spinlock);
uint16_t topic_id = 0;
@@ -1194,14 +1122,14 @@ int mqtt_ng_publish(struct mqtt_ng_client *client,
}
if (client->max_msg_size && PUBLISH_SP_SIZE + mqtt_ng_publish_size(topic, msg_len, topic_id) > client->max_msg_size) {
- mws_error(client->log, "Message too big for server: %zu", msg_len);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Message too big for server: %zu", msg_len);
return MQTT_NG_MSGGEN_MSG_TOO_BIG;
}
- TRY_GENERATE_MESSAGE(mqtt_ng_generate_publish, client, topic, topic_free, msg, msg_free, msg_len, publish_flags, packet_id, topic_id);
+ TRY_GENERATE_MESSAGE(mqtt_ng_generate_publish, topic, topic_free, msg, msg_free, msg_len, publish_flags, packet_id, topic_id);
}
-static inline size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_count)
+static size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_count)
{
size_t len = 2 /* Packet Identifier */ + 1 /* Properties Length TODO for now fixed 0 */;
len += sub_count * (2 /* topic filter string length */ + 1 /* [MQTT-3.8.3.1] Subscription Options Byte */);
@@ -1212,7 +1140,7 @@ static inline size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_co
return len;
}
-int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, struct mqtt_sub *subs, size_t sub_count)
+int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, struct mqtt_sub *subs, size_t sub_count)
{
// >> START THE RODEO <<
transaction_buffer_transaction_start(trx_buf);
@@ -1247,7 +1175,7 @@ int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, mqtt_wss_log_
for (size_t i = 0; i < sub_count; i++) {
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
PACK_2B_INT(&trx_buf->hdr_buffer, strlen(subs[i].topic), frag);
- if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, subs[i].topic, strlen(subs[i].topic), subs[i].topic_free, &frag))
+ if (_optimized_add(&trx_buf->hdr_buffer, subs[i].topic, strlen(subs[i].topic), subs[i].topic_free, &frag))
goto fail_rollback;
BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
*WRITE_POS(frag) = subs[i].options;
@@ -1264,12 +1192,11 @@ fail_rollback:
int mqtt_ng_subscribe(struct mqtt_ng_client *client, struct mqtt_sub *subs, size_t sub_count)
{
- TRY_GENERATE_MESSAGE(mqtt_ng_generate_subscribe, client, subs, sub_count);
+ TRY_GENERATE_MESSAGE(mqtt_ng_generate_subscribe, subs, sub_count);
}
-int mqtt_ng_generate_disconnect(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, uint8_t reason_code)
+int mqtt_ng_generate_disconnect(struct transaction_buffer *trx_buf, uint8_t reason_code)
{
- (void) log_ctx;
// >> START THE RODEO <<
transaction_buffer_transaction_start(trx_buf);
@@ -1308,12 +1235,11 @@ fail_rollback:
int mqtt_ng_disconnect(struct mqtt_ng_client *client, uint8_t reason_code)
{
- TRY_GENERATE_MESSAGE(mqtt_ng_generate_disconnect, client, reason_code);
+ TRY_GENERATE_MESSAGE(mqtt_ng_generate_disconnect, reason_code);
}
-static int mqtt_generate_puback(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, uint16_t packet_id, uint8_t reason_code)
+static int mqtt_generate_puback(struct transaction_buffer *trx_buf, uint16_t packet_id, uint8_t reason_code)
{
- (void) log_ctx;
// >> START THE RODEO <<
transaction_buffer_transaction_start(trx_buf);
@@ -1353,7 +1279,7 @@ fail_rollback:
static int mqtt_ng_puback(struct mqtt_ng_client *client, uint16_t packet_id, uint8_t reason_code)
{
- TRY_GENERATE_MESSAGE(mqtt_generate_puback, client, packet_id, reason_code);
+ TRY_GENERATE_MESSAGE(mqtt_generate_puback, packet_id, reason_code);
}
int mqtt_ng_ping(struct mqtt_ng_client *client)
@@ -1370,7 +1296,6 @@ int mqtt_ng_ping(struct mqtt_ng_client *client)
#define MQTT_NG_CLIENT_PROTOCOL_ERROR -1
#define MQTT_NG_CLIENT_SERVER_RETURNED_ERROR -2
#define MQTT_NG_CLIENT_NOT_IMPL_YET -3
-#define MQTT_NG_CLIENT_OOM -4
#define MQTT_NG_CLIENT_INTERNAL_ERROR -5
#define BUF_READ_CHECK_AT_LEAST(buf, x) \
@@ -1379,10 +1304,10 @@ int mqtt_ng_ping(struct mqtt_ng_client *client)
#define vbi_parser_reset_ctx(ctx) memset(ctx, 0, sizeof(struct mqtt_vbi_parser_ctx))
-static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data, mqtt_wss_log_ctx_t log)
+static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data)
{
if (ctx->bytes > MQTT_VBI_MAXBYTES - 1) {
- mws_error(log, "MQTT Variable Byte Integer can't be longer than %d bytes", MQTT_VBI_MAXBYTES);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT Variable Byte Integer can't be longer than %d bytes", MQTT_VBI_MAXBYTES);
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
}
if (!ctx->bytes || ctx->data[ctx->bytes-1] & MQTT_VBI_CONTINUATION_FLAG) {
@@ -1394,7 +1319,7 @@ static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data, mqtt_w
}
if (mqtt_vbi_to_uint32(ctx->data, &ctx->result)) {
- mws_error(log, "MQTT Variable Byte Integer failed to be parsed.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT Variable Byte Integer failed to be parsed.");
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
}
@@ -1480,12 +1405,12 @@ struct mqtt_property *get_property_by_id(struct mqtt_property *props, uint8_t pr
}
// Parses [MQTT-2.2.2]
-static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t data, mqtt_wss_log_ctx_t log)
+static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t data)
{
int rc;
switch (ctx->state) {
case PROPERTIES_LENGTH:
- rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data, log);
+ rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data);
if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
ctx->properties_length = ctx->vbi_parser_ctx.result;
ctx->bytes_consumed += ctx->vbi_parser_ctx.bytes;
@@ -1534,7 +1459,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
ctx->state = PROPERTY_TYPE_STR_BIN_LEN;
break;
default:
- mws_error(log, "Unsupported property type %d for property id %d.", (int)ctx->tail->type, (int)ctx->tail->id);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Unsupported property type %d for property id %d.", (int)ctx->tail->type, (int)ctx->tail->id);
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
}
break;
@@ -1552,7 +1477,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
ctx->state = PROPERTY_TYPE_STR;
break;
default:
- mws_error(log, "Unexpected datatype in PROPERTY_TYPE_STR_BIN_LEN %d", (int)ctx->tail->type);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Unexpected datatype in PROPERTY_TYPE_STR_BIN_LEN %d", (int)ctx->tail->type);
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
break;
@@ -1577,7 +1502,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
ctx->state = PROPERTY_NEXT;
break;
case PROPERTY_TYPE_VBI:
- rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data, log);
+ rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data);
if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
ctx->tail->data.uint32 = ctx->vbi_parser_ctx.result;
ctx->bytes_consumed += ctx->vbi_parser_ctx.bytes;
@@ -1627,9 +1552,9 @@ static int parse_connack_varhdr(struct mqtt_ng_client *client)
mqtt_properties_parser_ctx_reset(&parser->properties_parser);
break;
case MQTT_PARSE_VARHDR_PROPS:
- return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
+ return parse_properties_array(&parser->properties_parser, parser->received_data);
default:
- ERROR("invalid state for connack varhdr parser");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for connack varhdr parser");
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1653,9 +1578,9 @@ static int parse_disconnect_varhdr(struct mqtt_ng_client *client)
mqtt_properties_parser_ctx_reset(&parser->properties_parser);
break;
case MQTT_PARSE_VARHDR_PROPS:
- return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
+ return parse_properties_array(&parser->properties_parser, parser->received_data);
default:
- ERROR("invalid state for connack varhdr parser");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for connack varhdr parser");
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1691,9 +1616,9 @@ static int parse_puback_varhdr(struct mqtt_ng_client *client)
mqtt_properties_parser_ctx_reset(&parser->properties_parser);
/* FALLTHROUGH */
case MQTT_PARSE_VARHDR_PROPS:
- return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
+ return parse_properties_array(&parser->properties_parser, parser->received_data);
default:
- ERROR("invalid state for puback varhdr parser");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for puback varhdr parser");
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1716,7 +1641,7 @@ static int parse_suback_varhdr(struct mqtt_ng_client *client)
mqtt_properties_parser_ctx_reset(&parser->properties_parser);
/* FALLTHROUGH */
case MQTT_PARSE_VARHDR_PROPS:
- rc = parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
+ rc = parse_properties_array(&parser->properties_parser, parser->received_data);
if (rc != MQTT_NG_CLIENT_PARSE_DONE)
return rc;
parser->mqtt_parsed_len += parser->properties_parser.bytes_consumed;
@@ -1737,7 +1662,7 @@ static int parse_suback_varhdr(struct mqtt_ng_client *client)
return MQTT_NG_CLIENT_NEED_MORE_BYTES;
default:
- ERROR("invalid state for suback varhdr parser");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for suback varhdr parser");
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1761,8 +1686,6 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
break;
}
publish->topic = callocz(1, publish->topic_len + 1 /* add 0x00 */);
- if (publish->topic == NULL)
- return MQTT_NG_CLIENT_OOM;
parser->varhdr_state = MQTT_PARSE_VARHDR_TOPICNAME;
/* FALLTHROUGH */
case MQTT_PARSE_VARHDR_TOPICNAME:
@@ -1788,7 +1711,7 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
parser->mqtt_parsed_len += 2;
/* FALLTHROUGH */
case MQTT_PARSE_VARHDR_PROPS:
- rc = parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
+ rc = parse_properties_array(&parser->properties_parser, parser->received_data);
if (rc != MQTT_NG_CLIENT_PARSE_DONE)
return rc;
parser->mqtt_parsed_len += parser->properties_parser.bytes_consumed;
@@ -1798,7 +1721,7 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
if (parser->mqtt_fixed_hdr_remaining_length < parser->mqtt_parsed_len) {
freez(publish->topic);
publish->topic = NULL;
- ERROR("Error parsing PUBLISH message");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error parsing PUBLISH message");
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
}
publish->data_len = parser->mqtt_fixed_hdr_remaining_length - parser->mqtt_parsed_len;
@@ -1809,18 +1732,12 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
BUF_READ_CHECK_AT_LEAST(parser->received_data, publish->data_len);
publish->data = mallocz(publish->data_len);
- if (publish->data == NULL) {
- freez(publish->topic);
- publish->topic = NULL;
- return MQTT_NG_CLIENT_OOM;
- }
-
rbuf_pop(parser->received_data, publish->data, publish->data_len);
parser->mqtt_parsed_len += publish->data_len;
return MQTT_NG_CLIENT_PARSE_DONE;
default:
- ERROR("invalid state for publish varhdr parser");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for publish varhdr parser");
return MQTT_NG_CLIENT_INTERNAL_ERROR;
}
return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1840,7 +1757,7 @@ static int parse_data(struct mqtt_ng_client *client)
parser->state = MQTT_PARSE_FIXED_HEADER_LEN;
break;
case MQTT_PARSE_FIXED_HEADER_LEN:
- rc = vbi_parser_parse(&parser->vbi_parser, parser->received_data, client->log);
+ rc = vbi_parser_parse(&parser->vbi_parser, parser->received_data);
if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
parser->mqtt_fixed_hdr_remaining_length = parser->vbi_parser.result;
parser->state = MQTT_PARSE_VARIABLE_HEADER;
@@ -1883,10 +1800,11 @@ static int parse_data(struct mqtt_ng_client *client)
return rc;
case MQTT_CPT_PINGRESP:
if (parser->mqtt_fixed_hdr_remaining_length) {
- ERROR ("PINGRESP has to be 0 Remaining Length."); // [MQTT-3.13.1]
+ nd_log(NDLS_DAEMON, NDLP_ERR, "PINGRESP has to be 0 Remaining Length."); // [MQTT-3.13.1]
return MQTT_NG_CLIENT_PROTOCOL_ERROR;
}
parser->state = MQTT_PARSE_MQTT_PACKET_DONE;
+ ping_timeout = 0;
break;
case MQTT_CPT_DISCONNECT:
rc = parse_disconnect_varhdr(client);
@@ -1896,7 +1814,7 @@ static int parse_data(struct mqtt_ng_client *client)
}
return rc;
default:
- ERROR("Parsing Control Packet Type %" PRIu8 " not implemented yet.", get_control_packet_type(parser->mqtt_control_packet_type));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Parsing Control Packet Type %" PRIu8 " not implemented yet.", get_control_packet_type(parser->mqtt_control_packet_type));
rbuf_bump_tail(parser->received_data, parser->mqtt_fixed_hdr_remaining_length);
parser->state = MQTT_PARSE_MQTT_PACKET_DONE;
return MQTT_NG_CLIENT_NOT_IMPL_YET;
@@ -1916,12 +1834,12 @@ static int parse_data(struct mqtt_ng_client *client)
// return -1 on error
// return 0 if there is fragment set
static int mqtt_ng_next_to_send(struct mqtt_ng_client *client) {
- if (client->client_state == CONNECT_PENDING) {
+ if (client->client_state == MQTT_STATE_CONNECT_PENDING) {
client->main_buffer.sending_frag = client->connect_msg;
- client->client_state = CONNECTING;
+ client->client_state = MQTT_STATE_CONNECTING;
return 0;
}
- if (client->client_state != CONNECTED)
+ if (client->client_state != MQTT_STATE_CONNECTED)
return -1;
struct buffer_fragment *frag = BUFFER_FIRST_FRAG(&client->main_buffer.hdr_buffer);
@@ -1959,7 +1877,7 @@ static int send_fragment(struct mqtt_ng_client *client) {
if (bytes)
processed = client->send_fnc_ptr(client->user_ctx, ptr, bytes);
else
- WARN("This fragment was fully sent already. This should not happen!");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "This fragment was fully sent already. This should not happen!");
frag->sent += processed;
if (frag->sent != frag->len)
@@ -1967,11 +1885,11 @@ static int send_fragment(struct mqtt_ng_client *client) {
if (frag->flags & BUFFER_FRAG_MQTT_PACKET_TAIL) {
client->time_of_last_send = time(NULL);
- pthread_mutex_lock(&client->stats_mutex);
+ spinlock_lock(&client->stats_spinlock);
if (client->main_buffer.sending_frag != &ping_frag)
client->stats.tx_messages_queued--;
client->stats.tx_messages_sent++;
- pthread_mutex_unlock(&client->stats_mutex);
+ spinlock_unlock(&client->stats_spinlock);
client->main_buffer.sending_frag = NULL;
return 1;
}
@@ -1995,7 +1913,7 @@ static void try_send_all(struct mqtt_ng_client *client) {
} while(send_all_message_fragments(client) >= 0);
}
-static inline void mark_message_for_gc(struct buffer_fragment *frag)
+static void mark_message_for_gc(struct buffer_fragment *frag)
{
while (frag) {
frag->flags |= BUFFER_FRAG_GARBAGE_COLLECT;
@@ -2013,7 +1931,7 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
while (frag) {
if ( (frag->flags & BUFFER_FRAG_MQTT_PACKET_HEAD) && frag->packet_id == packet_id) {
if (!frag->sent) {
- ERROR("Received packet_id (%" PRIu16 ") belongs to MQTT packet which was not yet sent!", packet_id);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Received packet_id (%" PRIu16 ") belongs to MQTT packet which was not yet sent!", packet_id);
UNLOCK_HDR_BUFFER(&client->main_buffer);
return 1;
}
@@ -2023,7 +1941,7 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
}
frag = frag->next;
}
- ERROR("Received packet_id (%" PRIu16 ") is unknown!", packet_id);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Received packet_id (%" PRIu16 ") is unknown!", packet_id);
UNLOCK_HDR_BUFFER(&client->main_buffer);
return 1;
}
@@ -2031,110 +1949,113 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
int handle_incoming_traffic(struct mqtt_ng_client *client)
{
int rc;
+ while ((rc = parse_data(client)) == MQTT_NG_CLIENT_OK_CALL_AGAIN) {
+ ;
+ }
+ if (rc != MQTT_NG_CLIENT_MQTT_PACKET_DONE)
+ return rc;
+
struct mqtt_publish *pub;
- while( (rc = parse_data(client)) == MQTT_NG_CLIENT_OK_CALL_AGAIN );
- if ( rc == MQTT_NG_CLIENT_MQTT_PACKET_DONE ) {
- struct mqtt_property *prop;
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("MQTT Packet Parsed Successfully!");
-#endif
- pthread_mutex_lock(&client->stats_mutex);
- client->stats.rx_messages_rcvd++;
- pthread_mutex_unlock(&client->stats_mutex);
-
- switch (get_control_packet_type(client->parser.mqtt_control_packet_type)) {
- case MQTT_CPT_CONNACK:
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("Received CONNACK");
-#endif
- LOCK_HDR_BUFFER(&client->main_buffer);
- mark_message_for_gc(client->connect_msg);
- UNLOCK_HDR_BUFFER(&client->main_buffer);
- client->connect_msg = NULL;
- if (client->client_state != CONNECTING) {
- ERROR("Received unexpected CONNACK");
- client->client_state = ERROR;
- return MQTT_NG_CLIENT_PROTOCOL_ERROR;
- }
- if ((prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_MAX_PKT_SIZE)) != NULL) {
- INFO("MQTT server limits message size to %" PRIu32, prop->data.uint32);
- client->max_msg_size = prop->data.uint32;
- }
- if (client->connack_callback)
- client->connack_callback(client->user_ctx, client->parser.mqtt_packet.connack.reason_code);
- if (!client->parser.mqtt_packet.connack.reason_code) {
- INFO("MQTT Connection Accepted By Server");
- client->client_state = CONNECTED;
- break;
- }
- client->client_state = ERROR;
- return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
- case MQTT_CPT_PUBACK:
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("Received PUBACK %" PRIu16, client->parser.mqtt_packet.puback.packet_id);
-#endif
- if (mark_packet_acked(client, client->parser.mqtt_packet.puback.packet_id))
- return MQTT_NG_CLIENT_PROTOCOL_ERROR;
- if (client->puback_callback)
- client->puback_callback(client->parser.mqtt_packet.puback.packet_id);
- break;
- case MQTT_CPT_PINGRESP:
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("Received PINGRESP");
-#endif
- break;
- case MQTT_CPT_SUBACK:
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("Received SUBACK %" PRIu16, client->parser.mqtt_packet.suback.packet_id);
-#endif
- if (mark_packet_acked(client, client->parser.mqtt_packet.suback.packet_id))
- return MQTT_NG_CLIENT_PROTOCOL_ERROR;
+ struct mqtt_property *prop;
+ spinlock_lock(&client->stats_spinlock);
+ client->stats.rx_messages_rcvd++;
+ spinlock_unlock(&client->stats_spinlock);
+
+ uint8_t ctrl_packet_type = get_control_packet_type(client->parser.mqtt_control_packet_type);
+ switch (ctrl_packet_type) {
+ case MQTT_CPT_CONNACK:
+ LOCK_HDR_BUFFER(&client->main_buffer);
+ mark_message_for_gc(client->connect_msg);
+ UNLOCK_HDR_BUFFER(&client->main_buffer);
+
+ client->connect_msg = NULL;
+
+ if (client->client_state != MQTT_STATE_CONNECTING) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Received unexpected CONNACK");
+ client->client_state = MQTT_STATE_ERROR;
+ return MQTT_NG_CLIENT_PROTOCOL_ERROR;
+ }
+
+ if ((prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_MAX_PKT_SIZE)) != NULL) {
+ nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT server limits message size to %" PRIu32, prop->data.uint32);
+ client->max_msg_size = prop->data.uint32;
+ }
+
+ if (client->connack_callback)
+ client->connack_callback(client->user_ctx, client->parser.mqtt_packet.connack.reason_code);
+ if (!client->parser.mqtt_packet.connack.reason_code) {
+ nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT Connection Accepted By Server");
+ client->client_state = MQTT_STATE_CONNECTED;
break;
- case MQTT_CPT_PUBLISH:
-#ifdef MQTT_DEBUG_VERBOSE
- DEBUG("Recevied PUBLISH");
-#endif
- pub = &client->parser.mqtt_packet.publish;
- if (pub->qos > 1) {
- freez(pub->topic);
- freez(pub->data);
- return MQTT_NG_CLIENT_NOT_IMPL_YET;
- }
- if ( pub->qos == 1 && (rc = mqtt_ng_puback(client, pub->packet_id, 0)) ) {
- client->client_state = ERROR;
- ERROR("Error generating PUBACK reply for PUBLISH");
- return rc;
- }
- if ( (prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_TOPIC_ALIAS)) != NULL ) {
- // Topic Alias property was sent from server
- void *topic_ptr;
- if (!c_rhash_get_ptr_by_uint64(client->rx_aliases, prop->data.uint8, &topic_ptr)) {
- if (pub->topic != NULL) {
- ERROR("We do not yet support topic alias reassignment");
- return MQTT_NG_CLIENT_NOT_IMPL_YET;
- }
- pub->topic = topic_ptr;
- } else {
- if (pub->topic == NULL) {
- ERROR("Topic alias with id %d unknown and topic not set by server!", prop->data.uint8);
- return MQTT_NG_CLIENT_PROTOCOL_ERROR;
- }
- c_rhash_insert_uint64_ptr(client->rx_aliases, prop->data.uint8, pub->topic);
+ }
+ client->client_state = MQTT_STATE_ERROR;
+ return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
+
+ case MQTT_CPT_PUBACK:
+ if (mark_packet_acked(client, client->parser.mqtt_packet.puback.packet_id))
+ return MQTT_NG_CLIENT_PROTOCOL_ERROR;
+ if (client->puback_callback)
+ client->puback_callback(client->parser.mqtt_packet.puback.packet_id);
+ break;
+
+ case MQTT_CPT_PINGRESP:
+ break;
+
+ case MQTT_CPT_SUBACK:
+ if (mark_packet_acked(client, client->parser.mqtt_packet.suback.packet_id))
+ return MQTT_NG_CLIENT_PROTOCOL_ERROR;
+ break;
+
+ case MQTT_CPT_PUBLISH:
+ pub = &client->parser.mqtt_packet.publish;
+
+ if (pub->qos > 1) {
+ freez(pub->topic);
+ freez(pub->data);
+ return MQTT_NG_CLIENT_NOT_IMPL_YET;
+ }
+
+ if ( pub->qos == 1 && ((rc = mqtt_ng_puback(client, pub->packet_id, 0))) ) {
+ client->client_state = MQTT_STATE_ERROR;
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error generating PUBACK reply for PUBLISH");
+ return rc;
+ }
+
+ if ( (prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_TOPIC_ALIAS)) != NULL ) {
+ // Topic Alias property was sent from server
+ void *topic_ptr;
+ if (!c_rhash_get_ptr_by_uint64(client->rx_aliases, prop->data.uint8, &topic_ptr)) {
+ if (pub->topic != NULL) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "We do not yet support topic alias reassignment");
+ return MQTT_NG_CLIENT_NOT_IMPL_YET;
}
+ pub->topic = topic_ptr;
+ } else {
+ if (pub->topic == NULL) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Topic alias with id %d unknown and topic not set by server!", prop->data.uint8);
+ return MQTT_NG_CLIENT_PROTOCOL_ERROR;
+ }
+ c_rhash_insert_uint64_ptr(client->rx_aliases, prop->data.uint8, pub->topic);
}
- if (client->msg_callback)
- client->msg_callback(pub->topic, pub->data, pub->data_len, pub->qos);
- // in case we have property topic alias and we have topic we take over the string
- // and add pointer to it into topic alias list
- if (prop == NULL)
- freez(pub->topic);
- freez(pub->data);
- return MQTT_NG_CLIENT_WANT_WRITE;
- case MQTT_CPT_DISCONNECT:
- INFO ("Got MQTT DISCONNECT control packet from server. Reason code: %d", (int)client->parser.mqtt_packet.disconnect.reason_code);
- client->client_state = DISCONNECTED;
- break;
- }
+ }
+
+ if (client->msg_callback)
+ client->msg_callback(pub->topic, pub->data, pub->data_len, pub->qos);
+ // in case we have property topic alias and we have topic we take over the string
+ // and add pointer to it into topic alias list
+ if (prop == NULL)
+ freez(pub->topic);
+ freez(pub->data);
+ return MQTT_NG_CLIENT_WANT_WRITE;
+
+ case MQTT_CPT_DISCONNECT:
+ nd_log(NDLS_DAEMON, NDLP_INFO, "Got MQTT DISCONNECT control packet from server. Reason code: %d", (int)client->parser.mqtt_packet.disconnect.reason_code);
+ client->client_state = MQTT_STATE_DISCONNECTED;
+ break;
+
+ default:
+ nd_log(NDLS_DAEMON, NDLP_INFO, "Got unknown control packet %u from server", ctrl_packet_type);
+ break;
}
return rc;
@@ -2142,10 +2063,10 @@ int handle_incoming_traffic(struct mqtt_ng_client *client)
int mqtt_ng_sync(struct mqtt_ng_client *client)
{
- if (client->client_state == RAW || client->client_state == DISCONNECTED)
+ if (client->client_state == MQTT_STATE_RAW || client->client_state == MQTT_STATE_DISCONNECTED)
return 0;
- if (client->client_state == ERROR)
+ if (client->client_state == MQTT_STATE_ERROR)
return 1;
LOCK_HDR_BUFFER(&client->main_buffer);
@@ -2182,9 +2103,9 @@ void mqtt_ng_set_max_mem(struct mqtt_ng_client *client, size_t bytes)
void mqtt_ng_get_stats(struct mqtt_ng_client *client, struct mqtt_ng_stats *stats)
{
- pthread_mutex_lock(&client->stats_mutex);
+ spinlock_lock(&client->stats_spinlock);
memcpy(stats, &client->stats, sizeof(struct mqtt_ng_stats));
- pthread_mutex_unlock(&client->stats_mutex);
+ spinlock_unlock(&client->stats_spinlock);
stats->tx_bytes_queued = 0;
stats->tx_buffer_reclaimable = 0;
@@ -2207,11 +2128,11 @@ void mqtt_ng_get_stats(struct mqtt_ng_client *client, struct mqtt_ng_stats *stat
int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
{
uint16_t idx;
- pthread_rwlock_wrlock(&client->tx_topic_aliases.rwlock);
+ spinlock_lock(&client->tx_topic_aliases.spinlock);
if (client->tx_topic_aliases.idx_assigned >= client->tx_topic_aliases.idx_max) {
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
- mws_error(client->log, "Tx topic alias indexes were exhausted (current version of the library doesn't support reassigning yet. Feel free to contribute.");
+ spinlock_unlock(&client->tx_topic_aliases.spinlock);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Tx topic alias indexes were exhausted (current version of the library doesn't support reassigning yet. Feel free to contribute.");
return 0; //0 is not a valid topic alias
}
@@ -2220,8 +2141,8 @@ int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
// this is not a problem for library but might be helpful to warn user
// as it might indicate bug in their program (but also might be expected)
idx = alias->idx;
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
- mws_debug(client->log, "%s topic \"%s\" already has alias set. Ignoring.", __FUNCTION__, topic);
+ spinlock_unlock(&client->tx_topic_aliases.spinlock);
+ nd_log(NDLS_DAEMON, NDLP_DEBUG, "%s topic \"%s\" already has alias set. Ignoring.", __FUNCTION__, topic);
return idx;
}
@@ -2232,6 +2153,6 @@ int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
c_rhash_insert_str_ptr(client->tx_topic_aliases.stoi_dict, topic, (void*)alias);
- pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
+ spinlock_unlock(&client->tx_topic_aliases.spinlock);
return idx;
}
diff --git a/src/aclk/mqtt_websockets/mqtt_ng.h b/src/aclk/mqtt_websockets/mqtt_ng.h
index 4b0584d58..c5f6d94cc 100644
--- a/src/aclk/mqtt_websockets/mqtt_ng.h
+++ b/src/aclk/mqtt_websockets/mqtt_ng.h
@@ -1,10 +1,5 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
+// SPDX-License-Identifier: GPL-3.0-or-later
-#include <stdint.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include "c-rbuf/cringbuffer.h"
#include "common_public.h"
#define MQTT_NG_MSGGEN_OK 0
@@ -15,7 +10,7 @@
#define MQTT_NG_MSGGEN_MSG_TOO_BIG 3
struct mqtt_ng_client;
-
+extern time_t ping_timeout;
/* Converts integer to MQTT Variable Byte Integer as per 1.5.5 of MQTT 5 specs
* @param input value to be converted
* @param output pointer to memory where output will be written to. Must allow up to 4 bytes to be written.
@@ -72,7 +67,6 @@ int mqtt_ng_ping(struct mqtt_ng_client *client);
typedef ssize_t (*mqtt_ng_send_fnc_t)(void *user_ctx, const void* buf, size_t len);
struct mqtt_ng_init {
- mqtt_wss_log_ctx_t log;
rbuf_t data_in;
mqtt_ng_send_fnc_t data_out_fnc;
void *user_ctx;
diff --git a/src/aclk/mqtt_websockets/mqtt_wss_client.c b/src/aclk/mqtt_websockets/mqtt_wss_client.c
index bb0e17262..5c576ced5 100644
--- a/src/aclk/mqtt_websockets/mqtt_wss_client.c
+++ b/src/aclk/mqtt_websockets/mqtt_wss_client.c
@@ -1,32 +1,24 @@
-// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
+#include "libnetdata/libnetdata.h"
#include "mqtt_wss_client.h"
#include "mqtt_ng.h"
#include "ws_client.h"
#include "common_internal.h"
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <poll.h>
-#include <string.h>
-#include <time.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <openssl/err.h>
-#include <openssl/ssl.h>
+#include "../aclk.h"
#define PIPE_READ_END 0
#define PIPE_WRITE_END 1
#define POLLFD_SOCKET 0
#define POLLFD_PIPE 1
+#define PING_TIMEOUT (60) //Expect a ping response within this time (seconds)
+time_t ping_timeout = 0;
+
#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110) && (SSLEAY_VERSION_NUMBER >= OPENSSL_VERSION_097)
#include <openssl/conf.h>
#endif
@@ -69,6 +61,8 @@ char *util_openssl_ret_err(int err)
return "SSL_ERROR_SYSCALL";
case SSL_ERROR_SSL:
return "SSL_ERROR_SSL";
+ default:
+ break;
}
return "UNKNOWN";
}
@@ -76,8 +70,6 @@ char *util_openssl_ret_err(int err)
struct mqtt_wss_client_struct {
ws_client *ws_client;
- mqtt_wss_log_ctx_t log;
-
// immediate connection (e.g. proxy server)
char *host;
int port;
@@ -129,69 +121,49 @@ static void mws_connack_callback_ng(void *user_ctx, int code)
switch(code) {
case 0:
client->mqtt_connected = 1;
- return;
+ break;
//TODO manual labor: all the CONNACK error codes with some nice error message
default:
- mws_error(client->log, "MQTT CONNACK returned error %d", code);
- return;
+ nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT CONNACK returned error %d", code);
+ break;
}
}
static ssize_t mqtt_send_cb(void *user_ctx, const void* buf, size_t len)
{
mqtt_wss_client client = user_ctx;
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "mqtt_pal_sendall(len=%d)", len);
-#endif
int ret = ws_client_send(client->ws_client, WS_OP_BINARY_FRAME, buf, len);
- if (ret >= 0 && (size_t)ret != len) {
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Not complete message sent (Msg=%d,Sent=%d). Need to arm POLLOUT!", len, ret);
-#endif
+ if (ret >= 0 && (size_t)ret != len)
client->mqtt_didnt_finish_write = 1;
- }
return ret;
}
-mqtt_wss_client mqtt_wss_new(const char *log_prefix,
- mqtt_wss_log_callback_t log_callback,
- msg_callback_fnc_t msg_callback,
- void (*puback_callback)(uint16_t packet_id))
+mqtt_wss_client mqtt_wss_new(
+ msg_callback_fnc_t msg_callback,
+ void (*puback_callback)(uint16_t packet_id))
{
- mqtt_wss_log_ctx_t log;
-
- log = mqtt_wss_log_ctx_create(log_prefix, log_callback);
- if(!log)
- return NULL;
-
SSL_library_init();
SSL_load_error_strings();
mqtt_wss_client client = callocz(1, sizeof(struct mqtt_wss_client_struct));
- if (!client) {
- mws_error(log, "OOM alocating mqtt_wss_client");
- goto fail;
- }
spinlock_init(&client->stat_lock);
client->msg_callback = msg_callback;
client->puback_callback = puback_callback;
- client->ws_client = ws_client_new(0, &client->target_host, log);
+ client->ws_client = ws_client_new(0, &client->target_host);
if (!client->ws_client) {
- mws_error(log, "Error creating ws_client");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error creating ws_client");
goto fail_1;
}
- client->log = log;
-
#ifdef __APPLE__
if (pipe(client->write_notif_pipe)) {
#else
if (pipe2(client->write_notif_pipe, O_CLOEXEC /*| O_DIRECT*/)) {
#endif
- mws_error(log, "Couldn't create pipe");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Couldn't create pipe");
goto fail_2;
}
@@ -201,7 +173,6 @@ mqtt_wss_client mqtt_wss_new(const char *log_prefix,
client->poll_fds[POLLFD_SOCKET].events = POLLIN;
struct mqtt_ng_init settings = {
- .log = log,
.data_in = client->ws_client->buf_to_mqtt,
.data_out_fnc = &mqtt_send_cb,
.user_ctx = client,
@@ -209,22 +180,14 @@ mqtt_wss_client mqtt_wss_new(const char *log_prefix,
.puback_callback = puback_callback,
.msg_callback = msg_callback
};
- if ( (client->mqtt = mqtt_ng_init(&settings)) == NULL ) {
- mws_error(log, "Error initializing internal MQTT client");
- goto fail_3;
- }
+ client->mqtt = mqtt_ng_init(&settings);
return client;
-fail_3:
- close(client->write_notif_pipe[PIPE_WRITE_END]);
- close(client->write_notif_pipe[PIPE_READ_END]);
fail_2:
ws_client_destroy(client->ws_client);
fail_1:
freez(client);
-fail:
- mqtt_wss_log_ctx_destroy(log);
return NULL;
}
@@ -265,30 +228,25 @@ void mqtt_wss_destroy(mqtt_wss_client client)
if (client->sockfd > 0)
close(client->sockfd);
- mqtt_wss_log_ctx_destroy(client->log);
freez(client);
}
static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
- SSL *ssl;
- X509 *err_cert;
- mqtt_wss_client client;
- int err = 0, depth;
- char *err_str;
+ int err = 0;
- ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
- client = SSL_get_ex_data(ssl, 0);
+ SSL* ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ mqtt_wss_client client = SSL_get_ex_data(ssl, 0);
// TODO handle depth as per https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
if (!preverify_ok) {
err = X509_STORE_CTX_get_error(ctx);
- depth = X509_STORE_CTX_get_error_depth(ctx);
- err_cert = X509_STORE_CTX_get_current_cert(ctx);
- err_str = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
+ int depth = X509_STORE_CTX_get_error_depth(ctx);
+ X509* err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ char* err_str = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
- mws_error(client->log, "verify error:num=%d:%s:depth=%d:%s", err,
+ nd_log(NDLS_DAEMON, NDLP_ERR, "verify error:num=%d:%s:depth=%d:%s", err,
X509_verify_cert_error_string(err), depth, err_str);
freez(err_str);
@@ -298,7 +256,7 @@ static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
client->ssl_flags & MQTT_WSS_SSL_ALLOW_SELF_SIGNED)
{
preverify_ok = 1;
- mws_error(client->log, "Self Signed Certificate Accepted as the connection was "
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Self Signed Certificate Accepted as the connection was "
"requested with MQTT_WSS_SSL_ALLOW_SELF_SIGNED");
}
@@ -312,16 +270,14 @@ static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
#define HTTP_HDR_TERMINATOR "\x0D\x0A\x0D\x0A"
#define HTTP_CODE_LEN 4
#define HTTP_REASON_MAX_LEN 512
-static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
+static int http_parse_reply(rbuf_t buf)
{
- char *ptr;
char http_code_s[4];
- int http_code;
int idx;
if (rbuf_memcmp_n(buf, PROXY_HTTP, strlen(PROXY_HTTP))) {
if (rbuf_memcmp_n(buf, PROXY_HTTP10, strlen(PROXY_HTTP10))) {
- mws_error(client->log, "http_proxy expected reply with \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy expected reply with \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
return 1;
}
}
@@ -329,39 +285,37 @@ static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
rbuf_bump_tail(buf, strlen(PROXY_HTTP));
if (!rbuf_pop(buf, http_code_s, 1) || http_code_s[0] != 0x20) {
- mws_error(client->log, "http_proxy missing space after \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy missing space after \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
return 2;
}
if (!rbuf_pop(buf, http_code_s, HTTP_CODE_LEN)) {
- mws_error(client->log, "http_proxy missing HTTP code");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy missing HTTP code");
return 3;
}
for (int i = 0; i < HTTP_CODE_LEN - 1; i++)
if (http_code_s[i] > 0x39 || http_code_s[i] < 0x30) {
- mws_error(client->log, "http_proxy HTTP code non numeric");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy HTTP code non numeric");
return 4;
}
http_code_s[HTTP_CODE_LEN - 1] = 0;
- http_code = atoi(http_code_s);
+ int http_code = str2i(http_code_s);
// TODO check if we ever have more headers here
rbuf_find_bytes(buf, HTTP_ENDLINE, strlen(HTTP_ENDLINE), &idx);
if (idx >= HTTP_REASON_MAX_LEN) {
- mws_error(client->log, "http_proxy returned reason that is too long");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy returned reason that is too long");
return 5;
}
if (http_code != 200) {
- ptr = mallocz(idx + 1);
- if (!ptr)
- return 6;
+ char *ptr = mallocz(idx + 1);
rbuf_pop(buf, ptr, idx);
ptr[idx] = 0;
- mws_error(client->log, "http_proxy returned error code %d \"%s\"", http_code, ptr);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy returned error code %d \"%s\"", http_code, ptr);
freez(ptr);
return 7;
}/* else
@@ -374,52 +328,11 @@ static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
rbuf_bump_tail(buf, strlen(HTTP_HDR_TERMINATOR));
if (rbuf_bytes_available(buf)) {
- mws_error(client->log, "http_proxy unexpected trailing bytes after end of HTTP hdr");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy unexpected trailing bytes after end of HTTP hdr");
return 8;
}
- mws_debug(client->log, "http_proxy CONNECT succeeded");
- return 0;
-}
-
-#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
-static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
-{
- EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
-
- if (ctx != NULL) {
- memset(ctx, 0, sizeof(*ctx));
- }
- return ctx;
-}
-static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
-{
- OPENSSL_free(ctx);
- return;
-}
-#endif
-
-inline static int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
-{
- int len;
- unsigned char *str = out;
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- EVP_EncodeInit(ctx);
- EVP_EncodeUpdate(ctx, str, outl, in, in_len);
- str += *outl;
- EVP_EncodeFinal(ctx, str, &len);
- *outl += len;
-
- str = out;
- while(*str) {
- if (*str != 0x0D && *str != 0x0A)
- *out++ = *str++;
- else
- str++;
- }
- *out = 0;
-
- EVP_ENCODE_CTX_free(ctx);
+ nd_log(NDLS_DAEMON, NDLP_DEBUG, "http_proxy CONNECT succeeded");
return 0;
}
@@ -430,13 +343,12 @@ static int http_proxy_connect(mqtt_wss_client client)
rbuf_t r_buf = rbuf_create(4096);
if (!r_buf)
return 1;
- char *r_buf_ptr;
size_t r_buf_linear_insert_capacity;
poll_fd.fd = client->sockfd;
poll_fd.events = POLLIN;
- r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
+ char *r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
snprintf(r_buf_ptr, r_buf_linear_insert_capacity,"%s %s:%d %s" HTTP_ENDLINE "Host: %s" HTTP_ENDLINE, PROXY_CONNECT,
client->target_host, client->target_port, PROXY_HTTP, client->target_host);
write(client->sockfd, r_buf_ptr, strlen(r_buf_ptr));
@@ -445,7 +357,7 @@ static int http_proxy_connect(mqtt_wss_client client)
size_t creds_plain_len = strlen(client->proxy_uname) + strlen(client->proxy_passwd) + 2;
char *creds_plain = mallocz(creds_plain_len);
if (!creds_plain) {
- mws_error(client->log, "OOM creds_plain");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "OOM creds_plain");
rc = 6;
goto cleanup;
}
@@ -456,7 +368,7 @@ static int http_proxy_connect(mqtt_wss_client client)
char *creds_base64 = mallocz(creds_base64_len + 1);
if (!creds_base64) {
freez(creds_plain);
- mws_error(client->log, "OOM creds_base64");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "OOM creds_base64");
rc = 6;
goto cleanup;
}
@@ -466,8 +378,7 @@ static int http_proxy_connect(mqtt_wss_client client)
*ptr++ = ':';
strcpy(ptr, client->proxy_passwd);
- int b64_len;
- base64_encode_helper((unsigned char*)creds_base64, &b64_len, (unsigned char*)creds_plain, strlen(creds_plain));
+ (void) netdata_base64_encode((unsigned char*)creds_base64, (unsigned char*)creds_plain, strlen(creds_plain));
freez(creds_plain);
r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
@@ -482,13 +393,13 @@ static int http_proxy_connect(mqtt_wss_client client)
// or timeout
while ((rc = poll(&poll_fd, 1, 1000)) >= 0) {
if (!rc) {
- mws_error(client->log, "http_proxy timeout waiting reply from proxy server");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy timeout waiting reply from proxy server");
rc = 2;
goto cleanup;
}
r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
if (!r_buf_ptr) {
- mws_error(client->log, "http_proxy read ring buffer full");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy read ring buffer full");
rc = 3;
goto cleanup;
}
@@ -496,20 +407,20 @@ static int http_proxy_connect(mqtt_wss_client client)
if (errno == EWOULDBLOCK || errno == EAGAIN) {
continue;
}
- mws_error(client->log, "http_proxy error reading from socket \"%s\"", strerror(errno));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy error reading from socket \"%s\"", strerror(errno));
rc = 4;
goto cleanup;
}
rbuf_bump_head(r_buf, rc);
if (rbuf_find_bytes(r_buf, HTTP_HDR_TERMINATOR, strlen(HTTP_HDR_TERMINATOR), &rc)) {
rc = 0;
- if (http_parse_reply(client, r_buf))
+ if (http_parse_reply(r_buf))
rc = 5;
goto cleanup;
}
}
- mws_error(client->log, "proxy negotiation poll error \"%s\"", strerror(errno));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "proxy negotiation poll error \"%s\"", strerror(errno));
rc = 5;
cleanup:
rbuf_free(r_buf);
@@ -522,11 +433,11 @@ int mqtt_wss_connect(
int port,
struct mqtt_connect_params *mqtt_params,
int ssl_flags,
- struct mqtt_wss_proxy *proxy,
+ const struct mqtt_wss_proxy *proxy,
bool *fallback_ipv4)
{
if (!mqtt_params) {
- mws_error(client->log, "mqtt_params can't be null!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_params can't be null!");
return -1;
}
@@ -583,7 +494,7 @@ int mqtt_wss_connect(
struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
int fd = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, client->host, 0, port_str, &timeout, fallback_ipv4);
if (fd < 0) {
- mws_error(client->log, "Could not connect to remote endpoint \"%s\", port %d.\n", client->host, port);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Could not connect to remote endpoint \"%s\", port %d.\n", client->host, port);
return -3;
}
@@ -598,12 +509,12 @@ int mqtt_wss_connect(
int flag = 1;
int result = setsockopt(client->sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
if (result < 0)
- mws_error(client->log, "Could not dissable NAGLE");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Could not dissable NAGLE");
client->poll_fds[POLLFD_SOCKET].fd = client->sockfd;
if (fcntl(client->sockfd, F_SETFL, fcntl(client->sockfd, F_GETFL, 0) | O_NONBLOCK) == -1) {
- mws_error(client->log, "Error setting O_NONBLOCK to TCP socket. \"%s\"", strerror(errno));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error setting O_NONBLOCK to TCP socket. \"%s\"", strerror(errno));
return -8;
}
@@ -619,7 +530,7 @@ int mqtt_wss_connect(
SSL_library_init();
#else
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) != 1) {
- mws_error(client->log, "Failed to initialize SSL");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to initialize SSL");
return -1;
};
#endif
@@ -636,7 +547,7 @@ int mqtt_wss_connect(
SSL_CTX_set_default_verify_paths(client->ssl_ctx);
SSL_CTX_set_verify(client->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, cert_verify_callback);
} else
- mws_error(client->log, "SSL Certificate checking completely disabled!!!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL Certificate checking completely disabled!!!");
#ifdef MQTT_WSS_DEBUG
if(client->ssl_ctx_keylog_cb)
@@ -646,7 +557,7 @@ int mqtt_wss_connect(
client->ssl = SSL_new(client->ssl_ctx);
if (!(client->ssl_flags & MQTT_WSS_SSL_DONT_CHECK_CERTS)) {
if (!SSL_set_ex_data(client->ssl, 0, client)) {
- mws_error(client->log, "Could not SSL_set_ex_data");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Could not SSL_set_ex_data");
return -4;
}
}
@@ -654,27 +565,27 @@ int mqtt_wss_connect(
SSL_set_connect_state(client->ssl);
if (!SSL_set_tlsext_host_name(client->ssl, client->target_host)) {
- mws_error(client->log, "Error setting TLS SNI host");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error setting TLS SNI host");
return -7;
}
result = SSL_connect(client->ssl);
if (result != -1 && result != 1) {
- mws_error(client->log, "SSL could not connect");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL could not connect");
return -5;
}
if (result == -1) {
int ec = SSL_get_error(client->ssl, result);
if (ec != SSL_ERROR_WANT_READ && ec != SSL_ERROR_WANT_WRITE) {
- mws_error(client->log, "Failed to start SSL connection");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to start SSL connection");
return -6;
}
}
client->mqtt_keepalive = (mqtt_params->keep_alive ? mqtt_params->keep_alive : 400);
- mws_info(client->log, "Going to connect using internal MQTT 5 implementation");
+ nd_log(NDLS_DAEMON, NDLP_INFO, "Going to connect using internal MQTT 5 implementation");
struct mqtt_auth_properties auth;
auth.client_id = (char*)mqtt_params->clientid;
auth.client_id_free = NULL;
@@ -694,7 +605,7 @@ int mqtt_wss_connect(
int ret = mqtt_ng_connect(client->mqtt, &auth, mqtt_params->will_msg ? &lwt : NULL, 1, client->mqtt_keepalive);
if (ret) {
- mws_error(client->log, "Error generating MQTT connect");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error generating MQTT connect");
return 1;
}
@@ -703,7 +614,7 @@ int mqtt_wss_connect(
// wait till MQTT connection is established
while (!client->mqtt_connected) {
if(mqtt_wss_service(client, -1)) {
- mws_error(client->log, "Error connecting to MQTT WSS server \"%s\", port %d.", host, port);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Error connecting to MQTT WSS server \"%s\", port %d.", host, port);
return 2;
}
}
@@ -716,14 +627,14 @@ int mqtt_wss_connect(
#define NSEC_PER_MSEC 1000000ULL
#define NSEC_PER_SEC 1000000000ULL
-static inline uint64_t boottime_usec(mqtt_wss_client client) {
+static uint64_t boottime_usec(void) {
struct timespec ts;
#if defined(__APPLE__) || defined(__FreeBSD__)
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
#else
if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
#endif
- mws_error(client->log, "clock_gettimte failed");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "clock_gettimte failed");
return 0;
}
return (uint64_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
@@ -732,7 +643,7 @@ static inline uint64_t boottime_usec(mqtt_wss_client client) {
#define MWS_TIMED_OUT 1
#define MWS_ERROR 2
#define MWS_OK 0
-static inline const char *mqtt_wss_error_tos(int ec)
+static const char *mqtt_wss_error_tos(int ec)
{
switch(ec) {
case MWS_TIMED_OUT:
@@ -745,13 +656,12 @@ static inline const char *mqtt_wss_error_tos(int ec)
}
-static inline int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
+static int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
{
- uint64_t exit_by = boottime_usec(client) + (timeout_ms * NSEC_PER_MSEC);
- uint64_t now;
+ uint64_t exit_by = boottime_usec() + (timeout_ms * NSEC_PER_MSEC);
client->poll_fds[POLLFD_SOCKET].events |= POLLOUT; // TODO when entering mwtt_wss_service use out buffer size to arm POLLOUT
while (rbuf_bytes_available(client->ws_client->buf_write)) {
- now = boottime_usec(client);
+ const uint64_t now = boottime_usec();
if (now >= exit_by)
return MWS_TIMED_OUT;
if (mqtt_wss_service(client, exit_by - now))
@@ -762,15 +672,13 @@ static inline int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
{
- int ret;
-
// block application from sending more MQTT messages
client->mqtt_disconnecting = 1;
// send whatever was left at the time of calling this function
- ret = mqtt_wss_service_all(client, timeout_ms / 4);
+ int ret = mqtt_wss_service_all(client, timeout_ms / 4);
if(ret)
- mws_error(client->log,
+ nd_log(NDLS_DAEMON, NDLP_ERR,
"Error while trying to send all remaining data in an attempt "
"to gracefully disconnect! EC=%d Desc:\"%s\"",
ret,
@@ -782,7 +690,7 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
ret = mqtt_wss_service_all(client, timeout_ms / 4);
if(ret)
- mws_error(client->log,
+ nd_log(NDLS_DAEMON, NDLP_ERR,
"Error while trying to send MQTT disconnect message in an attempt "
"to gracefully disconnect! EC=%d Desc:\"%s\"",
ret,
@@ -795,7 +703,7 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
if(ret) {
// Some MQTT/WSS servers will close socket on receipt of MQTT disconnect and
// do not wait for WebSocket to be closed properly
- mws_warn(client->log,
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
"Error while trying to send WebSocket disconnect message in an attempt "
"to gracefully disconnect! EC=%d Desc:\"%s\".",
ret,
@@ -810,22 +718,19 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
client->sockfd = -1;
}
-static inline void mqtt_wss_wakeup(mqtt_wss_client client)
+static void mqtt_wss_wakeup(mqtt_wss_client client)
{
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "mqtt_wss_wakup - forcing wake up of main loop");
-#endif
write(client->write_notif_pipe[PIPE_WRITE_END], " ", 1);
}
#define THROWAWAY_BUF_SIZE 32
char throwaway[THROWAWAY_BUF_SIZE];
-static inline void util_clear_pipe(int fd)
+static void util_clear_pipe(int fd)
{
(void)read(fd, throwaway, THROWAWAY_BUF_SIZE);
}
-static inline void set_socket_pollfds(mqtt_wss_client client, int ssl_ret) {
+static void set_socket_pollfds(mqtt_wss_client client, int ssl_ret) {
if (ssl_ret == SSL_ERROR_WANT_WRITE)
client->poll_fds[POLLFD_SOCKET].events |= POLLOUT;
if (ssl_ret == SSL_ERROR_WANT_READ)
@@ -836,27 +741,25 @@ static int handle_mqtt_internal(mqtt_wss_client client)
{
int rc = mqtt_ng_sync(client->mqtt);
if (rc) {
- mws_error(client->log, "mqtt_ng_sync returned %d != 0", rc);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_ng_sync returned %d != 0", rc);
client->mqtt_connected = 0;
return 1;
}
return 0;
}
-#define SEC_TO_MSEC 1000
-static inline long long int t_till_next_keepalive_ms(mqtt_wss_client client)
+static int t_till_next_keepalive_ms(mqtt_wss_client client)
{
time_t last_send = mqtt_ng_last_send_time(client->mqtt);
- long long int next_mqtt_keep_alive = (last_send * SEC_TO_MSEC)
- + (client->mqtt_keepalive * (SEC_TO_MSEC * 0.75 /* SEND IN ADVANCE */));
- return(next_mqtt_keep_alive - (time(NULL) * SEC_TO_MSEC));
+ time_t next_mqtt_keep_alive = last_send + client->mqtt_keepalive * 0.75;
+ return ((next_mqtt_keep_alive - now_realtime_sec()) * MSEC_PER_SEC);
}
#ifdef MQTT_WSS_CPUSTATS
-static inline uint64_t mqtt_wss_now_usec(mqtt_wss_client client) {
+static uint64_t mqtt_wss_now_usec(void) {
struct timespec ts;
if(clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
- mws_error(client->log, "clock_gettime(CLOCK_MONOTONIC, &timespec) failed.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "clock_gettime(CLOCK_MONOTONIC, &timespec) failed.");
return 0;
}
return (uint64_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
@@ -871,63 +774,51 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
int send_keepalive = 0;
#ifdef MQTT_WSS_CPUSTATS
- uint64_t t1,t2;
- t1 = mqtt_wss_now_usec(client);
-#endif
-
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, ">>>>> mqtt_wss_service <<<<<");
- mws_debug(client->log, "Waiting for events: %s%s%s",
- (client->poll_fds[POLLFD_SOCKET].events & POLLIN) ? "SOCKET_POLLIN " : "",
- (client->poll_fds[POLLFD_SOCKET].events & POLLOUT) ? "SOCKET_POLLOUT " : "",
- (client->poll_fds[POLLFD_PIPE].events & POLLIN) ? "PIPE_POLLIN" : "" );
+ uint64_t t2;
+ uint64_t t1 = mqtt_wss_now_usec();
#endif
// Check user requested TO doesn't interfere with MQTT keep alives
- long long int till_next_keep_alive = t_till_next_keepalive_ms(client);
- if (client->mqtt_connected && (timeout_ms < 0 || timeout_ms >= till_next_keep_alive)) {
- #ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Shortening Timeout requested %d to %lld to ensure keep-alive can be sent", timeout_ms, till_next_keep_alive);
- #endif
- timeout_ms = till_next_keep_alive;
- send_keepalive = 1;
+ if (!ping_timeout) {
+ int till_next_keep_alive = t_till_next_keepalive_ms(client);
+ if (till_next_keep_alive < 0)
+ till_next_keep_alive = 0;
+ if (client->mqtt_connected && (timeout_ms < 0 || timeout_ms >= till_next_keep_alive)) {
+ timeout_ms = till_next_keep_alive;
+ send_keepalive = 1;
+ }
}
#ifdef MQTT_WSS_CPUSTATS
- t2 = mqtt_wss_now_usec(client);
+ t2 = mqtt_wss_now_usec();
client->stats.time_keepalive += t2 - t1;
#endif
if ((ret = poll(client->poll_fds, 2, timeout_ms >= 0 ? timeout_ms : -1)) < 0) {
if (errno == EINTR) {
- mws_warn(client->log, "poll interrupted by EINTR");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "poll interrupted by EINTR");
return 0;
}
- mws_error(client->log, "poll error \"%s\"", strerror(errno));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "poll error \"%s\"", strerror(errno));
return -2;
}
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Poll events happened: %s%s%s%s",
- (client->poll_fds[POLLFD_SOCKET].revents & POLLIN) ? "SOCKET_POLLIN " : "",
- (client->poll_fds[POLLFD_SOCKET].revents & POLLOUT) ? "SOCKET_POLLOUT " : "",
- (client->poll_fds[POLLFD_PIPE].revents & POLLIN) ? "PIPE_POLLIN " : "",
- (!ret) ? "POLL_TIMEOUT" : "");
-#endif
-
#ifdef MQTT_WSS_CPUSTATS
- t1 = mqtt_wss_now_usec(client);
+ t1 = mqtt_wss_now_usec();
#endif
if (ret == 0) {
+ time_t now = now_realtime_sec();
if (send_keepalive) {
// otherwise we shortened the timeout ourselves to take care of
// MQTT keep alives
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Forcing MQTT Ping/keep-alive");
-#endif
mqtt_ng_ping(client->mqtt);
+ ping_timeout = now + PING_TIMEOUT;
} else {
+ if (ping_timeout && ping_timeout < now) {
+ disconnect_req = ACLK_PING_TIMEOUT;
+ ping_timeout = 0;
+ }
// if poll timed out and user requested timeout was being used
// return here let user do his work and he will call us back soon
return 0;
@@ -935,7 +826,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
}
#ifdef MQTT_WSS_CPUSTATS
- t2 = mqtt_wss_now_usec(client);
+ t2 = mqtt_wss_now_usec();
client->stats.time_keepalive += t2 - t1;
#endif
@@ -943,9 +834,6 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
if ((ptr = rbuf_get_linear_insert_range(client->ws_client->buf_read, &size))) {
if((ret = SSL_read(client->ssl, ptr, size)) > 0) {
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "SSL_Read: Read %d.", ret);
-#endif
spinlock_lock(&client->stat_lock);
client->stats.bytes_rx += ret;
spinlock_unlock(&client->stat_lock);
@@ -953,22 +841,19 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
} else {
int errnobkp = errno;
ret = SSL_get_error(client->ssl, ret);
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Read Err: %s", util_openssl_ret_err(ret));
-#endif
set_socket_pollfds(client, ret);
if (ret != SSL_ERROR_WANT_READ &&
ret != SSL_ERROR_WANT_WRITE) {
- mws_error(client->log, "SSL_read error: %d %s", ret, util_openssl_ret_err(ret));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read error: %d %s", ret, util_openssl_ret_err(ret));
if (ret == SSL_ERROR_SYSCALL)
- mws_error(client->log, "SSL_read SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
return MQTT_WSS_ERR_CONN_DROP;
}
}
}
#ifdef MQTT_WSS_CPUSTATS
- t1 = mqtt_wss_now_usec(client);
+ t1 = mqtt_wss_now_usec();
client->stats.time_read_socket += t1 - t2;
#endif
@@ -976,18 +861,20 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
switch(ret) {
case WS_CLIENT_PROTOCOL_ERROR:
return MQTT_WSS_ERR_PROTO_WS;
+
case WS_CLIENT_NEED_MORE_BYTES:
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "WSCLIENT WANT READ");
-#endif
client->poll_fds[POLLFD_SOCKET].events |= POLLIN;
break;
+
case WS_CLIENT_CONNECTION_CLOSED:
return MQTT_WSS_ERR_CONN_DROP;
+
+ default:
+ return MQTT_WSS_ERR_PROTO_WS;
}
#ifdef MQTT_WSS_CPUSTATS
- t2 = mqtt_wss_now_usec(client);
+ t2 = mqtt_wss_now_usec();
client->stats.time_process_websocket += t2 - t1;
#endif
@@ -1002,18 +889,12 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
}
#ifdef MQTT_WSS_CPUSTATS
- t1 = mqtt_wss_now_usec(client);
+ t1 = mqtt_wss_now_usec();
client->stats.time_process_mqtt += t1 - t2;
#endif
if ((ptr = rbuf_get_linear_read_range(client->ws_client->buf_write, &size))) {
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Have data to write to SSL");
-#endif
if ((ret = SSL_write(client->ssl, ptr, size)) > 0) {
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "SSL_Write: Written %d of avail %d.", ret, size);
-#endif
spinlock_lock(&client->stat_lock);
client->stats.bytes_tx += ret;
spinlock_unlock(&client->stat_lock);
@@ -1021,15 +902,12 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
} else {
int errnobkp = errno;
ret = SSL_get_error(client->ssl, ret);
-#ifdef DEBUG_ULTRA_VERBOSE
- mws_debug(client->log, "Write Err: %s", util_openssl_ret_err(ret));
-#endif
set_socket_pollfds(client, ret);
if (ret != SSL_ERROR_WANT_READ &&
ret != SSL_ERROR_WANT_WRITE) {
- mws_error(client->log, "SSL_write error: %d %s", ret, util_openssl_ret_err(ret));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write error: %d %s", ret, util_openssl_ret_err(ret));
if (ret == SSL_ERROR_SYSCALL)
- mws_error(client->log, "SSL_write SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
+ nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
return MQTT_WSS_ERR_CONN_DROP;
}
}
@@ -1039,7 +917,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
util_clear_pipe(client->write_notif_pipe[PIPE_READ_END]);
#ifdef MQTT_WSS_CPUSTATS
- t2 = mqtt_wss_now_usec(client);
+ t2 = mqtt_wss_now_usec();
client->stats.time_write_socket += t2 - t1;
#endif
@@ -1056,12 +934,12 @@ int mqtt_wss_publish5(mqtt_wss_client client,
uint16_t *packet_id)
{
if (client->mqtt_disconnecting) {
- mws_error(client->log, "mqtt_wss is disconnecting can't publish");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_wss is disconnecting can't publish");
return 1;
}
if (!client->mqtt_connected) {
- mws_error(client->log, "MQTT is offline. Can't send message.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT is offline. Can't send message.");
return 1;
}
uint8_t mqtt_flags = 0;
@@ -1072,7 +950,7 @@ int mqtt_wss_publish5(mqtt_wss_client client,
int rc = mqtt_ng_publish(client->mqtt, topic, topic_free, msg, msg_free, msg_len, mqtt_flags, packet_id);
if (rc == MQTT_NG_MSGGEN_MSG_TOO_BIG)
- return MQTT_WSS_ERR_TOO_BIG_FOR_SERVER;
+ return MQTT_WSS_ERR_MSG_TOO_BIG;
mqtt_wss_wakeup(client);
@@ -1083,12 +961,12 @@ int mqtt_wss_subscribe(mqtt_wss_client client, char *topic, int max_qos_level)
{
(void)max_qos_level; //TODO now hardcoded
if (!client->mqtt_connected) {
- mws_error(client->log, "MQTT is offline. Can't subscribe.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT is offline. Can't subscribe.");
return 1;
}
if (client->mqtt_disconnecting) {
- mws_error(client->log, "mqtt_wss is disconnecting can't subscribe");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_wss is disconnecting can't subscribe");
return 1;
}
diff --git a/src/aclk/mqtt_websockets/mqtt_wss_client.h b/src/aclk/mqtt_websockets/mqtt_wss_client.h
index f0bdce98b..2fd94075d 100644
--- a/src/aclk/mqtt_websockets/mqtt_wss_client.h
+++ b/src/aclk/mqtt_websockets/mqtt_wss_client.h
@@ -1,56 +1,36 @@
-// SPDX-License-Identifier: GPL-3.0-only
-// Copyright (C) 2020 Timotej Šiškovič
+// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef MQTT_WSS_CLIENT_H
#define MQTT_WSS_CLIENT_H
-#include <stdbool.h>
-#include <stdint.h>
-#include <stddef.h> //size_t
-
-#include "mqtt_wss_log.h"
#include "common_public.h"
-// All OK call me at your earliest convinience
-#define MQTT_WSS_OK 0
-/* All OK, poll timeout you requested when calling mqtt_wss_service expired - you might want to know if timeout
- * happened or we got some data or handle same as MQTT_WSS_OK
- */
-#define MQTT_WSS_OK_TO 1
-// Connection was closed by remote
-#define MQTT_WSS_ERR_CONN_DROP -1
-// Error in MQTT protocol (e.g. malformed packet)
-#define MQTT_WSS_ERR_PROTO_MQTT -2
-// Error in WebSocket protocol (e.g. malformed packet)
-#define MQTT_WSS_ERR_PROTO_WS -3
-
-#define MQTT_WSS_ERR_TX_BUF_TOO_SMALL -4
-#define MQTT_WSS_ERR_RX_BUF_TOO_SMALL -5
-
-#define MQTT_WSS_ERR_TOO_BIG_FOR_SERVER -6
-// if client was initialized with MQTT 3 but MQTT 5 feature
-// was requested by user of library
-#define MQTT_WSS_ERR_CANT_DO -8
+
+#define MQTT_WSS_OK 0 // All OK call me at your earliest convinience
+#define MQTT_WSS_OK_TO 1 // All OK, poll timeout you requested when calling mqtt_wss_service expired
+ //you might want to know if timeout
+ //happened or we got some data or handle same as MQTT_WSS_OK
+#define MQTT_WSS_ERR_CONN_DROP -1 // Connection was closed by remote
+#define MQTT_WSS_ERR_PROTO_MQTT -2 // Error in MQTT protocol (e.g. malformed packet)
+#define MQTT_WSS_ERR_PROTO_WS -3 // Error in WebSocket protocol (e.g. malformed packet)
+#define MQTT_WSS_ERR_MSG_TOO_BIG -6 // Message size too big for server
+#define MQTT_WSS_ERR_CANT_DO -8 // if client was initialized with MQTT 3 but MQTT 5 feature
+ // was requested by user of library
typedef struct mqtt_wss_client_struct *mqtt_wss_client;
typedef void (*msg_callback_fnc_t)(const char *topic, const void *msg, size_t msglen, int qos);
+
/* Creates new instance of MQTT over WSS. Doesn't start connection.
- * @param log_prefix this is prefix to be used when logging to discern between multiple
- * mqtt_wss instances. Can be NULL.
- * @param log_callback is function pointer to fnc to be called when mqtt_wss wants
- * to log. This allows plugging this library into your own logging system/solution.
- * If NULL STDOUT/STDERR will be used.
* @param msg_callback is function pointer to function which will be called
* when application level message arrives from broker (for subscribed topics).
* Can be NULL if you are not interested about incoming messages.
* @param puback_callback is function pointer to function to be called when QOS1 Publish
* is acknowledged by server
*/
-mqtt_wss_client mqtt_wss_new(const char *log_prefix,
- mqtt_wss_log_callback_t log_callback,
- msg_callback_fnc_t msg_callback,
- void (*puback_callback)(uint16_t packet_id));
+mqtt_wss_client mqtt_wss_new(
+ msg_callback_fnc_t msg_callback,
+ void (*puback_callback)(uint16_t packet_id));
void mqtt_wss_set_max_buf_size(mqtt_wss_client client, size_t size);
@@ -76,7 +56,7 @@ int mqtt_wss_connect(
int port,
struct mqtt_connect_params *mqtt_params,
int ssl_flags,
- struct mqtt_wss_proxy *proxy,
+ const struct mqtt_wss_proxy *proxy,
bool *fallback_ipv4);
int mqtt_wss_service(mqtt_wss_client client, int timeout_ms);
void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms);
diff --git a/src/aclk/mqtt_websockets/mqtt_wss_log.c b/src/aclk/mqtt_websockets/mqtt_wss_log.c
deleted file mode 100644
index e5da76fcf..000000000
--- a/src/aclk/mqtt_websockets/mqtt_wss_log.c
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "mqtt_wss_log.h"
-#include "common_internal.h"
-
-struct mqtt_wss_log_ctx {
- mqtt_wss_log_callback_t extern_log_fnc;
- char *ctx_prefix;
- char *buffer;
- char *buffer_w_ptr;
- size_t buffer_bytes_avail;
-};
-
-#define LOG_BUFFER_SIZE 1024 * 4
-#define LOG_CTX_PREFIX_SEV_STR " : "
-#define LOG_CTX_PREFIX_LIMIT 15
-#define LOG_CTX_PREFIX_LIMIT_STR (LOG_CTX_PREFIX_LIMIT - (2 + strlen(LOG_CTX_PREFIX_SEV_STR))) // with [] characters and affixed ' ' it is total 15 chars
-#if (LOG_CTX_PREFIX_LIMIT * 10) > LOG_BUFFER_SIZE
-#error "LOG_BUFFER_SIZE too small"
-#endif
-mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback)
-{
- mqtt_wss_log_ctx_t ctx = callocz(1, sizeof(struct mqtt_wss_log_ctx));
- if(!ctx)
- return NULL;
-
- if(log_callback) {
- ctx->extern_log_fnc = log_callback;
- ctx->buffer = callocz(1, LOG_BUFFER_SIZE);
- if(!ctx->buffer)
- goto cleanup;
-
- ctx->buffer_w_ptr = ctx->buffer;
- if(ctx_prefix) {
- *(ctx->buffer_w_ptr++) = '[';
- strncpy(ctx->buffer_w_ptr, ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
- ctx->buffer_w_ptr += strnlen(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
- *(ctx->buffer_w_ptr++) = ']';
- }
- strcpy(ctx->buffer_w_ptr, LOG_CTX_PREFIX_SEV_STR);
- ctx->buffer_w_ptr += strlen(LOG_CTX_PREFIX_SEV_STR);
- // no term '\0' -> calloc is used
-
- ctx->buffer_bytes_avail = LOG_BUFFER_SIZE - strlen(ctx->buffer);
-
- return ctx;
- }
-
- if(ctx_prefix) {
- ctx->ctx_prefix = strndup(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
- if(!ctx->ctx_prefix)
- goto cleanup;
- }
-
- return ctx;
-
-cleanup:
- freez(ctx);
- return NULL;
-}
-
-void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx)
-{
- freez(ctx->ctx_prefix);
- freez(ctx->buffer);
- freez(ctx);
-}
-
-static inline char severity_to_c(int severity)
-{
- switch (severity) {
- case MQTT_WSS_LOG_FATAL:
- return 'F';
- case MQTT_WSS_LOG_ERROR:
- return 'E';
- case MQTT_WSS_LOG_WARN:
- return 'W';
- case MQTT_WSS_LOG_INFO:
- return 'I';
- case MQTT_WSS_LOG_DEBUG:
- return 'D';
- default:
- return '?';
- }
-}
-
-void mws_log(int severity, mqtt_wss_log_ctx_t ctx, const char *fmt, va_list args)
-{
- size_t size;
-
- if(ctx->extern_log_fnc) {
- size = vsnprintf(ctx->buffer_w_ptr, ctx->buffer_bytes_avail, fmt, args);
- *(ctx->buffer_w_ptr - 3) = severity_to_c(severity);
-
- ctx->extern_log_fnc(severity, ctx->buffer);
-
- if(size >= ctx->buffer_bytes_avail)
- mws_error(ctx, "Last message of this type was truncated! Consider what you log or increase LOG_BUFFER_SIZE if really needed.");
-
- return;
- }
-
- if(ctx->ctx_prefix)
- printf("[%s] ", ctx->ctx_prefix);
-
- printf("%c: ", severity_to_c(severity));
-
- vprintf(fmt, args);
- putchar('\n');
-}
-
-#define DEFINE_MWS_SEV_FNC(severity_fncname, severity) \
-void mws_ ## severity_fncname(mqtt_wss_log_ctx_t ctx, const char *fmt, ...) \
-{ \
- va_list args; \
- va_start(args, fmt); \
- mws_log(severity, ctx, fmt, args); \
- va_end(args); \
-}
-
-DEFINE_MWS_SEV_FNC(fatal, MQTT_WSS_LOG_FATAL)
-DEFINE_MWS_SEV_FNC(error, MQTT_WSS_LOG_ERROR)
-DEFINE_MWS_SEV_FNC(warn, MQTT_WSS_LOG_WARN )
-DEFINE_MWS_SEV_FNC(info, MQTT_WSS_LOG_INFO )
-DEFINE_MWS_SEV_FNC(debug, MQTT_WSS_LOG_DEBUG)
diff --git a/src/aclk/mqtt_websockets/mqtt_wss_log.h b/src/aclk/mqtt_websockets/mqtt_wss_log.h
deleted file mode 100644
index 6ae60d870..000000000
--- a/src/aclk/mqtt_websockets/mqtt_wss_log.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright: SPDX-License-Identifier: GPL-3.0-only
-
-#ifndef MQTT_WSS_LOG_H
-#define MQTT_WSS_LOG_H
-
-typedef enum mqtt_wss_log_type {
- MQTT_WSS_LOG_DEBUG = 0x01,
- MQTT_WSS_LOG_INFO = 0x02,
- MQTT_WSS_LOG_WARN = 0x03,
- MQTT_WSS_LOG_ERROR = 0x81,
- MQTT_WSS_LOG_FATAL = 0x88
-} mqtt_wss_log_type_t;
-
-typedef void (*mqtt_wss_log_callback_t)(mqtt_wss_log_type_t, const char*);
-
-typedef struct mqtt_wss_log_ctx *mqtt_wss_log_ctx_t;
-
-/** Creates logging context with optional prefix and optional callback
- * @param ctx_prefix String to be prefixed to every log message.
- * This is useful if multiple clients are instantiated to be able to
- * know which one this message belongs to. Can be `NULL` for no prefix.
- * @param log_callback Callback to be called instead of logging to
- * `STDOUT` or `STDERR` (if debug enabled otherwise silent). Callback has to be
- * pointer to function of `void function(mqtt_wss_log_type_t, const char*)` type.
- * If `NULL` default will be used (silent or STDERR/STDOUT).
- * @return mqtt_wss_log_ctx_t or `NULL` on error */
-mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback);
-
-/** Destroys logging context and cleans up the memory
- * @param ctx Context to destroy */
-void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx);
-
-void mws_fatal(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
-void mws_error(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
-void mws_warn (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
-void mws_info (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
-void mws_debug(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
-
-#endif /* MQTT_WSS_LOG_H */
diff --git a/src/aclk/mqtt_websockets/ws_client.c b/src/aclk/mqtt_websockets/ws_client.c
index a6b9b23f3..99ea266c8 100644
--- a/src/aclk/mqtt_websockets/ws_client.c
+++ b/src/aclk/mqtt_websockets/ws_client.c
@@ -1,103 +1,43 @@
-// Copyright (C) 2020 Timotej Šiškovič
-// SPDX-License-Identifier: GPL-3.0-only
-//
-// 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, version 3.
-//
-// 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 <https://www.gnu.org/licenses/>.
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <openssl/evp.h>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "libnetdata/libnetdata.h"
#include "ws_client.h"
#include "common_internal.h"
-#ifdef MQTT_WEBSOCKETS_DEBUG
-#include "../c-rbuf/src/ringbuffer_internal.h"
-#endif
-
-#define UNIT_LOG_PREFIX "ws_client: "
-#define FATAL(fmt, ...) mws_fatal(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define ERROR(fmt, ...) mws_error(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define WARN(fmt, ...) mws_warn (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define INFO(fmt, ...) mws_info (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-#define DEBUG(fmt, ...) mws_debug(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
-
const char *websocket_upgrage_hdr = "GET /mqtt HTTP/1.1\x0D\x0A"
"Host: %s\x0D\x0A"
"Upgrade: websocket\x0D\x0A"
"Connection: Upgrade\x0D\x0A"
"Sec-WebSocket-Key: %s\x0D\x0A"
- "Origin: http://example.com\x0D\x0A"
+ "Origin: \x0D\x0A"
"Sec-WebSocket-Protocol: mqtt\x0D\x0A"
"Sec-WebSocket-Version: 13\x0D\x0A\x0D\x0A";
const char *mqtt_protoid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
#define DEFAULT_RINGBUFFER_SIZE (1024*128)
-#define ENTROPY_SOURCE "/dev/urandom"
-ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log)
-{
- ws_client *client;
+ws_client *ws_client_new(size_t buf_size, char **host)
+{
if(!host)
return NULL;
- client = callocz(1, sizeof(ws_client));
- if (!client)
- return NULL;
-
+ ws_client *client = callocz(1, sizeof(ws_client));
client->host = host;
- client->log = log;
-
client->buf_read = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
- if (!client->buf_read)
- goto cleanup;
-
client->buf_write = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
- if (!client->buf_write)
- goto cleanup_1;
-
client->buf_to_mqtt = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
- if (!client->buf_to_mqtt)
- goto cleanup_2;
-
- client->entropy_fd = open(ENTROPY_SOURCE, O_RDONLY | O_CLOEXEC);
- if (client->entropy_fd < 1) {
- ERROR("Error opening entropy source \"" ENTROPY_SOURCE "\". Reason: \"%s\"", strerror(errno));
- goto cleanup_3;
- }
return client;
-
-cleanup_3:
- rbuf_free(client->buf_to_mqtt);
-cleanup_2:
- rbuf_free(client->buf_write);
-cleanup_1:
- rbuf_free(client->buf_read);
-cleanup:
- freez(client);
- return NULL;
}
void ws_client_free_headers(ws_client *client)
{
struct http_header *ptr = client->hs.headers;
- struct http_header *tmp;
while (ptr) {
- tmp = ptr;
+ struct http_header *tmp = ptr;
ptr = ptr->next;
freez(tmp);
}
@@ -112,7 +52,6 @@ void ws_client_destroy(ws_client *client)
ws_client_free_headers(client);
freez(client->hs.nonce_reply);
freez(client->hs.http_reply_msg);
- close(client->entropy_fd);
rbuf_free(client->buf_read);
rbuf_free(client->buf_write);
rbuf_free(client->buf_to_mqtt);
@@ -141,7 +80,7 @@ void ws_client_reset(ws_client *client)
int ws_client_add_http_header(ws_client *client, struct http_header *hdr)
{
if (client->hs.hdr_count > MAX_HTTP_HDR_COUNT) {
- ERROR("Too many HTTP response header fields");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Too many HTTP response header fields");
return -1;
}
@@ -156,7 +95,7 @@ int ws_client_add_http_header(ws_client *client, struct http_header *hdr)
return 0;
}
-int ws_client_want_write(ws_client *client)
+int ws_client_want_write(const ws_client *client)
{
return rbuf_bytes_available(client->buf_write);
}
@@ -165,78 +104,89 @@ int ws_client_want_write(ws_client *client)
#define TEMP_BUF_SIZE 4096
int ws_client_start_handshake(ws_client *client)
{
- nd_uuid_t nonce;
+ unsigned char nonce[WEBSOCKET_NONCE_SIZE];
char nonce_b64[256];
char second[TEMP_BUF_SIZE];
unsigned int md_len;
- unsigned char *digest;
+ unsigned char digest[EVP_MAX_MD_SIZE]; // EVP_MAX_MD_SIZE ensures enough space
EVP_MD_CTX *md_ctx;
const EVP_MD *md;
+ int rc = 1;
if(!client->host || !*client->host) {
- ERROR("Hostname has not been set. We should not be able to come here!");
- return 1;
- }
-
- uuid_generate_random(nonce);
- EVP_EncodeBlock((unsigned char *)nonce_b64, (const unsigned char *)nonce, WEBSOCKET_NONCE_SIZE);
- snprintf(second, TEMP_BUF_SIZE, websocket_upgrage_hdr, *client->host, nonce_b64);
-
- if(rbuf_bytes_free(client->buf_write) < strlen(second)) {
- ERROR("Write buffer capacity too low.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Hostname has not been set. We should not be able to come here!");
return 1;
}
- rbuf_push(client->buf_write, second, strlen(second));
- client->state = WS_HANDSHAKE;
-
- //Calculating expected Sec-WebSocket-Accept reply
- snprintf(second, TEMP_BUF_SIZE, "%s%s", nonce_b64, mqtt_protoid);
+ // Generate a random 16-byte nonce
+ os_random_bytes(nonce, sizeof(nonce));
+ // Initialize the digest context
#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110)
md_ctx = EVP_MD_CTX_create();
#else
md_ctx = EVP_MD_CTX_new();
#endif
if (md_ctx == NULL) {
- ERROR("Cant create EVP_MD Context");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Can't create EVP_MD context");
return 1;
}
- md = EVP_get_digestbyname("sha1");
+ md = EVP_sha1(); // Use SHA-1 for WebSocket handshake
if (!md) {
- ERROR("Unknown message digest");
- return 1;
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown message digest SHA-1");
+ goto exit_with_error;
}
- if ((digest = (unsigned char *)OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL) {
- ERROR("Cant alloc digest");
- return 1;
+ (void) netdata_base64_encode((unsigned char *) nonce_b64, nonce, WEBSOCKET_NONCE_SIZE);
+
+ // Format and push the upgrade header to the write buffer
+ size_t bytes = snprintf(second, TEMP_BUF_SIZE, websocket_upgrage_hdr, *client->host, nonce_b64);
+ if(rbuf_bytes_free(client->buf_write) < bytes) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Write buffer capacity too low.");
+ goto exit_with_error;
}
+ rbuf_push(client->buf_write, second, bytes);
+
+ client->state = WS_HANDSHAKE;
- EVP_DigestInit_ex(md_ctx, md, NULL);
- EVP_DigestUpdate(md_ctx, second, strlen(second));
- EVP_DigestFinal_ex(md_ctx, digest, &md_len);
+ // Create the expected Sec-WebSocket-Accept value
+ bytes = snprintf(second, TEMP_BUF_SIZE, "%s%s", nonce_b64, mqtt_protoid);
- EVP_EncodeBlock((unsigned char *)nonce_b64, digest, (int) md_len);
+ if (!EVP_DigestInit_ex(md_ctx, md, NULL)) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to initialize digest context");
+ goto exit_with_error;
+ }
+
+ if (!EVP_DigestUpdate(md_ctx, second, bytes)) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to update digest");
+ goto exit_with_error;
+ }
+
+ if (!EVP_DigestFinal_ex(md_ctx, digest, &md_len)) {
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to finalize digest");
+ goto exit_with_error;
+ }
+
+ (void) netdata_base64_encode((unsigned char *) nonce_b64, digest, md_len);
freez(client->hs.nonce_reply);
client->hs.nonce_reply = strdupz(nonce_b64);
+ rc = 0;
- OPENSSL_free(digest);
-
+exit_with_error:
#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110)
EVP_MD_CTX_destroy(md_ctx);
#else
EVP_MD_CTX_free(md_ctx);
#endif
- return 0;
+ return rc;
}
#define BUF_READ_MEMCMP_CONST(const, err) \
if (rbuf_memcmp_n(client->buf_read, const, strlen(const))) { \
- ERROR(err); \
+ nd_log(NDLS_DAEMON, NDLP_ERR, err); \
rbuf_flush(client->buf_read); \
return WS_CLIENT_PROTOCOL_ERROR; \
}
@@ -262,7 +212,7 @@ int ws_client_start_handshake(ws_client *client)
#define HTTP_HDR_LINE_CHECK_LIMIT(x) \
if ((x) >= MAX_HTTP_LINE_LENGTH) { \
- ERROR("HTTP line received is too long. Maximum is %d", MAX_HTTP_LINE_LENGTH); \
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP line received is too long. Maximum is %d", MAX_HTTP_LINE_LENGTH); \
return WS_CLIENT_PROTOCOL_ERROR; \
}
@@ -285,13 +235,13 @@ int ws_client_parse_handshake_resp(ws_client *client)
BUF_READ_CHECK_AT_LEAST(HTTP_SC_LENGTH); // "XXX " http return code
rbuf_pop(client->buf_read, buf, HTTP_SC_LENGTH);
if (buf[HTTP_SC_LENGTH - 1] != 0x20) {
- ERROR("HTTP status code received is not terminated by space (0x20)");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP status code received is not terminated by space (0x20)");
return WS_CLIENT_PROTOCOL_ERROR;
}
buf[HTTP_SC_LENGTH - 1] = 0;
client->hs.http_code = atoi(buf);
if (client->hs.http_code < 100 || client->hs.http_code >= 600) {
- ERROR("HTTP status code received not in valid range 100-600");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP status code received not in valid range 100-600");
return WS_CLIENT_PROTOCOL_ERROR;
}
client->hs.hdr_state = WS_HDR_ENDLINE;
@@ -330,16 +280,16 @@ int ws_client_parse_handshake_resp(ws_client *client)
ptr = rbuf_find_bytes(client->buf_read, HTTP_HDR_SEPARATOR, strlen(HTTP_HDR_SEPARATOR), &idx_sep);
if (!ptr || idx_sep > idx_crlf) {
- ERROR("Expected HTTP hdr field key/value separator \": \" before endline in non empty HTTP header line");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Expected HTTP hdr field key/value separator \": \" before endline in non empty HTTP header line");
return WS_CLIENT_PROTOCOL_ERROR;
}
if (idx_crlf == idx_sep + (int)strlen(HTTP_HDR_SEPARATOR)) {
- ERROR("HTTP Header value cannot be empty");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP Header value cannot be empty");
return WS_CLIENT_PROTOCOL_ERROR;
}
if (idx_sep > HTTP_HEADER_NAME_MAX_LEN) {
- ERROR("HTTP header too long (%d)", idx_sep);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP header too long (%d)", idx_sep);
return WS_CLIENT_PROTOCOL_ERROR;
}
@@ -347,23 +297,21 @@ int ws_client_parse_handshake_resp(ws_client *client)
hdr->key = ((char*)hdr) + sizeof(struct http_header);
hdr->value = hdr->key + idx_sep + 1;
- bytes = rbuf_pop(client->buf_read, hdr->key, idx_sep);
+ rbuf_pop(client->buf_read, hdr->key, idx_sep);
rbuf_bump_tail(client->buf_read, strlen(HTTP_HDR_SEPARATOR));
- bytes = rbuf_pop(client->buf_read, hdr->value, idx_crlf - idx_sep - strlen(HTTP_HDR_SEPARATOR));
+ rbuf_pop(client->buf_read, hdr->value, idx_crlf - idx_sep - strlen(HTTP_HDR_SEPARATOR));
rbuf_bump_tail(client->buf_read, strlen(WS_HTTP_NEWLINE));
for (int i = 0; hdr->key[i]; i++)
hdr->key[i] = tolower(hdr->key[i]);
-// DEBUG("HTTP header \"%s\" received. Value \"%s\"", hdr->key, hdr->value);
-
if (ws_client_add_http_header(client, hdr))
return WS_CLIENT_PROTOCOL_ERROR;
if (!strcmp(hdr->key, WS_CONN_ACCEPT)) {
if (strcmp(client->hs.nonce_reply, hdr->value)) {
- ERROR("Received NONCE \"%s\" does not match expected nonce of \"%s\"", hdr->value, client->hs.nonce_reply);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Received NONCE \"%s\" does not match expected nonce of \"%s\"", hdr->value, client->hs.nonce_reply);
return WS_CLIENT_PROTOCOL_ERROR;
}
client->hs.nonce_matched = 1;
@@ -373,21 +321,21 @@ int ws_client_parse_handshake_resp(ws_client *client)
case WS_HDR_PARSE_DONE:
if (!client->hs.nonce_matched) {
- ERROR("Missing " WS_CONN_ACCEPT " header");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Missing " WS_CONN_ACCEPT " header");
return WS_CLIENT_PROTOCOL_ERROR;
}
if (client->hs.http_code != 101) {
- ERROR("HTTP return code not 101. Received %d with msg \"%s\".", client->hs.http_code, client->hs.http_reply_msg);
+ nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP return code not 101. Received %d with msg \"%s\".", client->hs.http_code, client->hs.http_reply_msg);
return WS_CLIENT_PROTOCOL_ERROR;
}
client->state = WS_ESTABLISHED;
client->hs.hdr_state = WS_HDR_ALL_DONE;
- INFO("Websocket Connection Accepted By Server");
+ nd_log(NDLS_DAEMON, NDLP_INFO, "Websocket Connection Accepted By Server");
return WS_CLIENT_PARSING_DONE;
case WS_HDR_ALL_DONE:
- FATAL("This is error we should never come here!");
+ nd_log(NDLS_DAEMON, NDLP_CRIT, "This is error we should never come here!");
return WS_CLIENT_PROTOCOL_ERROR;
}
return 0;
@@ -397,7 +345,7 @@ int ws_client_parse_handshake_resp(ws_client *client)
#define WS_FINAL_FRAG BYTE_MSB
#define WS_PAYLOAD_MASKED BYTE_MSB
-static inline size_t get_ws_hdr_size(size_t payload_size)
+static size_t get_ws_hdr_size(size_t payload_size)
{
size_t hdr_len = 2 + 4 /*mask*/;
if(payload_size > 125)
@@ -408,7 +356,7 @@ static inline size_t get_ws_hdr_size(size_t payload_size)
}
#define MAX_POSSIBLE_HDR_LEN 14
-int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size)
+int ws_client_send(const ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size)
{
// TODO maybe? implement fragmenting, it is not necessary though
// as both tested MQTT brokers have no reuirement of one MQTT envelope
@@ -416,24 +364,16 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
// one big MQTT message as single fragmented WebSocket envelope
char hdr[MAX_POSSIBLE_HDR_LEN];
char *ptr = hdr;
- char *mask;
int size_written = 0;
size_t j = 0;
size_t w_buff_free = rbuf_bytes_free(client->buf_write);
size_t hdr_len = get_ws_hdr_size(size);
- if (w_buff_free < hdr_len * 2) {
-#ifdef DEBUG_ULTRA_VERBOSE
- DEBUG("Write buffer full. Can't write requested %d size.", size);
-#endif
+ if (w_buff_free < hdr_len * 2)
return 0;
- }
if (w_buff_free < (hdr_len + size)) {
-#ifdef DEBUG_ULTRA_VERBOSE
- DEBUG("Can't write whole MQTT packet of %d bytes into the buffer. Will do partial send of %d.", size, w_buff_free - hdr_len);
-#endif
size = w_buff_free - hdr_len;
hdr_len = get_ws_hdr_size(size);
// the actual needed header size might decrease if we cut number of bytes
@@ -459,12 +399,10 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
ptr += sizeof(be);
} else
*ptr++ |= size;
-
- mask = ptr;
- if (read(client->entropy_fd, mask, sizeof(uint32_t)) < (ssize_t)sizeof(uint32_t)) {
- ERROR("Unable to get mask from \"" ENTROPY_SOURCE "\"");
- return -2;
- }
+
+ char *mask = ptr;
+ uint32_t mask32 = os_random32() + 1;
+ memcpy(mask, &mask32, sizeof(mask32));
rbuf_push(client->buf_write, hdr, hdr_len);
@@ -490,7 +428,7 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
return size_written;
}
-static int check_opcode(ws_client *client,enum websocket_opcode oc)
+static int check_opcode(enum websocket_opcode oc)
{
switch(oc) {
case WS_OP_BINARY_FRAME:
@@ -498,34 +436,34 @@ static int check_opcode(ws_client *client,enum websocket_opcode oc)
case WS_OP_PING:
return 0;
case WS_OP_CONTINUATION_FRAME:
- FATAL("WS_OP_CONTINUATION_FRAME NOT IMPLEMENTED YET!!!!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_CONTINUATION_FRAME NOT IMPLEMENTED YET!!!!");
return 0;
case WS_OP_TEXT_FRAME:
- FATAL("WS_OP_TEXT_FRAME NOT IMPLEMENTED YET!!!!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_TEXT_FRAME NOT IMPLEMENTED YET!!!!");
return 0;
case WS_OP_PONG:
- FATAL("WS_OP_PONG NOT IMPLEMENTED YET!!!!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_PONG NOT IMPLEMENTED YET!!!!");
return 0;
default:
return WS_CLIENT_PROTOCOL_ERROR;
}
}
-static inline void ws_client_rx_post_hdr_state(ws_client *client)
+static void ws_client_rx_post_hdr_state(ws_client *client)
{
switch(client->rx.opcode) {
case WS_OP_BINARY_FRAME:
client->rx.parse_state = WS_PAYLOAD_DATA;
- return;
+ break;
case WS_OP_CONNECTION_CLOSE:
client->rx.parse_state = WS_PAYLOAD_CONNECTION_CLOSE;
- return;
+ break;
case WS_OP_PING:
client->rx.parse_state = WS_PAYLOAD_PING_REQ_PAYLOAD;
- return;
+ break;
default:
client->rx.parse_state = WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD;
- return;
+ break;
}
}
@@ -541,15 +479,15 @@ int ws_client_process_rx_ws(ws_client *client)
client->rx.opcode = buf[0] & (char)~BYTE_MSB;
if (!(buf[0] & (char)~WS_FINAL_FRAG)) {
- ERROR("Not supporting fragmented messages yet!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Not supporting fragmented messages yet!");
return WS_CLIENT_PROTOCOL_ERROR;
}
- if (check_opcode(client, client->rx.opcode) == WS_CLIENT_PROTOCOL_ERROR)
+ if (check_opcode(client->rx.opcode) == WS_CLIENT_PROTOCOL_ERROR)
return WS_CLIENT_PROTOCOL_ERROR;
if (buf[1] & (char)WS_PAYLOAD_MASKED) {
- ERROR("Mask is not allowed in Server->Client Websocket direction.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Mask is not allowed in Server->Client Websocket direction.");
return WS_CLIENT_PROTOCOL_ERROR;
}
@@ -584,12 +522,8 @@ int ws_client_process_rx_ws(ws_client *client)
if (!rbuf_bytes_available(client->buf_read))
return WS_CLIENT_NEED_MORE_BYTES;
char *insert = rbuf_get_linear_insert_range(client->buf_to_mqtt, &size);
- if (!insert) {
-#ifdef DEBUG_ULTRA_VERBOSE
- DEBUG("BUFFER TOO FULL. Avail %d req %d", (int)size, (int)remaining);
-#endif
+ if (!insert)
return WS_CLIENT_BUFFER_FULL;
- }
size = (size > remaining) ? remaining : size;
size = rbuf_pop(client->buf_read, insert, size);
rbuf_bump_head(client->buf_to_mqtt, size);
@@ -603,11 +537,11 @@ int ws_client_process_rx_ws(ws_client *client)
// b) 2byte reason code
// c) 2byte reason code followed by message
if (client->rx.payload_length == 1) {
- ERROR("WebScoket CONNECTION_CLOSE can't have payload of size 1");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "WebScoket CONNECTION_CLOSE can't have payload of size 1");
return WS_CLIENT_PROTOCOL_ERROR;
}
if (!client->rx.payload_length) {
- INFO("WebSocket server closed the connection without giving reason.");
+ nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection without giving reason.");
client->rx.parse_state = WS_PACKET_DONE;
break;
}
@@ -621,7 +555,7 @@ int ws_client_process_rx_ws(ws_client *client)
client->rx.payload_processed += sizeof(uint16_t);
if(client->rx.payload_processed == client->rx.payload_length) {
- INFO("WebSocket server closed the connection with EC=%d. Without message.",
+ nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection with EC=%d. Without message.",
client->rx.specific_data.op_close.ec);
client->rx.parse_state = WS_PACKET_DONE;
break;
@@ -640,7 +574,7 @@ int ws_client_process_rx_ws(ws_client *client)
client->rx.payload_length - client->rx.payload_processed);
}
client->rx.specific_data.op_close.reason[client->rx.payload_length] = 0;
- INFO("WebSocket server closed the connection with EC=%d and reason \"%s\"",
+ nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection with EC=%d and reason \"%s\"",
client->rx.specific_data.op_close.ec,
client->rx.specific_data.op_close.reason);
freez(client->rx.specific_data.op_close.reason);
@@ -649,14 +583,14 @@ int ws_client_process_rx_ws(ws_client *client)
break;
case WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD:
BUF_READ_CHECK_AT_LEAST(client->rx.payload_length);
- WARN("Skipping Websocket Packet of unsupported/unknown type");
+ nd_log(NDLS_DAEMON, NDLP_WARNING, "Skipping Websocket Packet of unsupported/unknown type");
if (client->rx.payload_length)
rbuf_bump_tail(client->buf_read, client->rx.payload_length);
client->rx.parse_state = WS_PACKET_DONE;
return WS_CLIENT_PARSING_DONE;
case WS_PAYLOAD_PING_REQ_PAYLOAD:
if (client->rx.payload_length > rbuf_get_capacity(client->buf_read) / 2) {
- ERROR("Ping arrived with payload which is too big!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Ping arrived with payload which is too big!");
return WS_CLIENT_INTERNAL_ERROR;
}
BUF_READ_CHECK_AT_LEAST(client->rx.payload_length);
@@ -666,7 +600,7 @@ int ws_client_process_rx_ws(ws_client *client)
// then attempt to send as soon as buffer space clears up
size = ws_client_send(client, WS_OP_PONG, client->rx.specific_data.ping_msg, client->rx.payload_length);
if (size != client->rx.payload_length) {
- ERROR("Unable to send the PONG as one packet back. Closing connection.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Unable to send the PONG as one packet back. Closing connection.");
return WS_CLIENT_PROTOCOL_ERROR;
}
client->rx.parse_state = WS_PACKET_DONE;
@@ -678,7 +612,7 @@ int ws_client_process_rx_ws(ws_client *client)
return WS_CLIENT_CONNECTION_CLOSED;
return WS_CLIENT_PARSING_DONE;
default:
- FATAL("Unknown parse state");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown parse state");
return WS_CLIENT_INTERNAL_ERROR;
}
return 0;
@@ -711,6 +645,8 @@ int ws_client_process(ws_client *client)
case WS_CLIENT_CONNECTION_CLOSED:
client->state = WS_CONN_CLOSED_GRACEFUL;
break;
+ default:
+ break;
}
// if ret == 0 we can continue parsing
// if ret == WS_CLIENT_PARSING_DONE we processed
@@ -719,13 +655,13 @@ int ws_client_process(ws_client *client)
} while (!ret || ret == WS_CLIENT_PARSING_DONE);
break;
case WS_ERROR:
- ERROR("ws_client is in error state. Restart the connection!");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "ws_client is in error state. Restart the connection!");
return WS_CLIENT_PROTOCOL_ERROR;
case WS_CONN_CLOSED_GRACEFUL:
- ERROR("Connection has been gracefully closed. Calling this is useless (and probably bug) until you reconnect again.");
+ nd_log(NDLS_DAEMON, NDLP_ERR, "Connection has been gracefully closed. Calling this is useless (and probably bug) until you reconnect again.");
return WS_CLIENT_CONNECTION_CLOSED;
default:
- FATAL("Unknown connection state! Probably memory corruption.");
+ nd_log(NDLS_DAEMON, NDLP_CRIT, "Unknown connection state! Probably memory corruption.");
return WS_CLIENT_INTERNAL_ERROR;
}
return ret;
diff --git a/src/aclk/mqtt_websockets/ws_client.h b/src/aclk/mqtt_websockets/ws_client.h
index 0ccbd29a8..67e5835a2 100644
--- a/src/aclk/mqtt_websockets/ws_client.h
+++ b/src/aclk/mqtt_websockets/ws_client.h
@@ -1,14 +1,8 @@
-// SPDX-License-Identifier: GPL-3.0-only
-// Copyright (C) 2020 Timotej Šiškovič
+// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef WS_CLIENT_H
#define WS_CLIENT_H
-#include "c-rbuf/cringbuffer.h"
-#include "mqtt_wss_log.h"
-
-#include <stdint.h>
-
#define WS_CLIENT_NEED_MORE_BYTES 0x10
#define WS_CLIENT_PARSING_DONE 0x11
#define WS_CLIENT_CONNECTION_CLOSED 0x12
@@ -98,23 +92,20 @@ typedef struct websocket_client {
// memory usage and remove one more memcpy buf_read->buf_to_mqtt
rbuf_t buf_to_mqtt; // RAW data for MQTT lib
- int entropy_fd;
-
// careful host is borrowed, don't free
char **host;
- mqtt_wss_log_ctx_t log;
} ws_client;
-ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log);
+ws_client *ws_client_new(size_t buf_size, char **host);
void ws_client_destroy(ws_client *client);
void ws_client_reset(ws_client *client);
int ws_client_start_handshake(ws_client *client);
-int ws_client_want_write(ws_client *client);
+int ws_client_want_write(const ws_client *client);
int ws_client_process(ws_client *client);
-int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
+int ws_client_send(const ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
#endif /* WS_CLIENT_H */