-
Notifications
You must be signed in to change notification settings - Fork 164
Feat[bmqp]: Add userAgent to ClientIdentity
#1036
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
pniedzielski
wants to merge
5
commits into
bloomberg:main
Choose a base branch
from
pniedzielski:feat/useragent
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98b91bf to
bac1ce7
Compare
Collaborator
Author
|
Example log messages from Note |
Collaborator
Author
|
And on the broker side: |
54f017c to
f65c095
Compare
pniedzielski
commented
Nov 25, 2025
pniedzielski
commented
Nov 25, 2025
f65c095 to
564c6ac
Compare
f9561eb to
f577834
Compare
f577834 to
f2cb004
Compare
The BlazingMQ project provides three SDKs for writing applications that send and receive messages from a BlazingMQ cluster: - the C++03 `libbmq` library, housed in this repository; - the Java `com.bloomberg.bmq` package; and - the Python `blazingmq` package. Of these, `libbmq` and `com.bloomberg.bmq` are separate, independent implementations of the BlazingMQ protocol, and `blazingmq` is a Cython wrapper around `libbmq`. Future SDKs, produced either by the BlazingMQ project or by the community, may take either road. It is useful telemetry to know which SDK language and version a client is connecting to a broker with, and the `ClientIdentity` generated type does partially provide this information, in the form of an `sdkLanguage` enumeration and an `sdkVersion` integer. These two fields are useful for programmatic checks on protocol compatibility, but for telemetry, we have found them to be insufficient. First, any SDK that wraps `libbmq`, like the Python `blazingmq` package, will advertise itself as an `E_CPP` client. `libbmq` provides no way for a client to override the SDK language and version it negotiates with, so `blazingmq` has no way to advertise itself as anything different. While it is useful to know what version of the underlying `libbmq` a Python client is connecting with, this leaves it difficult for us to distinguish between clients that are connecting directly using `libbmq`, or Python clients that are connecting using `blazingmq`. This problem will be true for any future SDK that wraps `libbmq`. Second, any new SDK that does not wrap `libbmq` will either need to choose from one of the existing `sdkLanguages` (or use `E_UNKNOWN`), or request a protocol change from BlazingMQ to add their language version. The same problem as above happens with the first option, while the second option is simply unscalable. This patch introduces a new optional field called `userAgent` to the `ClientIdentity` type that is sent during session negotiation. At the protocol level, this field is a free-form string, with which client libraries can identify themselves, and the broker does nothing more than log it along with the session negotiation message. This allows clients that do not wrap `libbmq` to identify themselves to the broker. This patch also teaches `libbmq` and `bmqbrkr` about this field, so they can send identifying version strings as their `userAgent`. At the moment, `libbmq` does provide any way to modify this field, so libraries that wrap `libbmq`, like the Python `blazingmq`, still suffer from the first problem noted above. A future patch will expose a way to modify the user agent (likely in restricted ways). Importantly, this field MUST NOT be used for anything more than telemetry, because clients do not need to specify it, and malicious client libraries can easily spoof their `userAgent` to be the same as other client libraries. Signed-off-by: Patrick M. Niedzielski <[email protected]>
This patch adds a new field `s_versionDotString` to the `Version` structs in `*scm_version` components, which stores a human-readable version string. This differs from the `version()` function, which has information identifying the package group or application prefixed to it. In principle, `s_versionDotString` could contain other information, like prerelease numbers if we adopt those, without breaking an compatibility for existing callers of `version()`. Signed-off-by: Patrick M. Niedzielski <[email protected]>
This patch changes user agents constructed by `libbmq` and the broker from forms like `libbmq:BLP_LIB_BMQ_99.99.99` to `libbmq:99.99.99‘. Signed-off-by: Patrick M. Niedzielski <[email protected]>
The BlazingMQ protocol now contains support for a user agent field
sent during session negotiation. This allows client libraries to
identify themselves for the purposes of broker telementry. However,
client libraries that wrap `libbmq`, like the open source `blazingmq`
Python package, are still forced to identify themselves as `libbmq`.
This patch exposes a `userAgentPrefix` option in
`bmqt::SessionOptions`, which is prefixed to the user agent that
`libbmq` constructs. This allows client libraries that are built with
`libbmq` to add their own version information that will be passed
along during session negotiation. Although we encourage users not to
set this, by making this option a prefix, we prevent users from
erasing `libbmq`’s version string, limiting the damage they can
accidentally do to telemetry. It is expected that libraries wrapping
`libbmq` can do something similar, in case further libraries wrap
them.
The setting exposed in this patch has further restrictions that are
not present in the protocol, to make sure that clients built on top of
`libbmq` do not accidentally write large/unprintable strings to the
broker log:
1. The user agent prefix must be less than 128 characters long.
This can be increased safely in the future if necessary, but it
is generous as is.
2. The user agent prefix must contain only printable ASCII
characters.
Example usage:
```
bmqt::SessionOptions options;
// ...
options.setUserAgentPrefix("myWrapperLib:1.2.3~unstable");
bmqa::Session session(options);
session.start();
// userAgent sent during session negotiation:
// myWrapperLib:1.2.3~unstable libbmq:99.99.99
```
Signed-off-by: Patrick M. Niedzielski <[email protected]>
f2cb004 to
bdbee72
Compare
bdbee72 to
9db9a7f
Compare
bmqtool is not a wrapper library, this is a cheap way to test that the user agent string sent to the broker contains both the user-specified `userAgentPrefix` string (which in this case will be `bmqtool`) and the `libbmq`-provided user agent string. Signed-off-by: Patrick M. Niedzielski <[email protected]>
9db9a7f to
62a3302
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The BlazingMQ project provides three SDKs for writing applications that send and receive messages from a BlazingMQ cluster:
libbmqlibrary, housed in this repository;com.bloomberg.bmqpackage; andblazingmqpackage.Of these,
libbmqandcom.bloomberg.bmqare separate, independent implementations of the BlazingMQ protocol, andblazingmqis a Cython wrapper aroundlibbmq. Future SDKs, produced either by the BlazingMQ project or by the community, may take either road.It is useful telemetry to know which SDK language and version a client is connecting to a broker with, and the
ClientIdentitygenerated type does partially provide this information, in the form of ansdkLanguageenumeration and ansdkVersioninteger. These two fields are useful for programmatic checks on protocol compatibility, but for telemetry, we have found them to be insufficient.First, any SDK that wraps
libbmq, like the Pythonblazingmqpackage, will advertise itself as anE_CPPclient.libbmqprovides no way for a client to override the SDK language and version it negotiates with, soblazingmqhas no way to advertise itself as anything different. While it is useful to know what version of the underlyinglibbmqa Python client is connecting with, this leaves it difficult for us to distinguish between clients that are connecting directly usinglibbmq, or Python clients that are connecting usingblazingmq. This problem will be true for any future SDK that wrapslibbmq.Second, any new SDK that does not wrap
libbmqwill either need to choose from one of the existingsdkLanguages(or useE_UNKNOWN), or request a protocol change from BlazingMQ to add their language version. The same problem as above happens with the first option, while the second option is simply unscalable.This pull request introduces a new optional field called
userAgentto theClientIdentitytype that is sent during session negotiation. At the protocol level, this field is a free-form string, with which client libraries can identify themselves, and the broker does nothing more than log it along with the session negotiation message. This allows clients that do not wraplibbmqto identify themselves to the broker.Importantly, this field MUST NOT be used for anything more than telemetry, because clients do not need to specify it, and malicious client libraries can easily spoof their
userAgentto be the same as other client libraries.The important changes in this PR:
*scm_versioncomponents, which gives us a nicer way of adding version information to the user agent.bmqpto add optional user agent field.userAgentPrefix, which is prefixed to the user agentlibbmqgenerates. This lets wrapping libraries add their own version information, while preserving the version oflibbmqthey're wrapping.libbmq,bmqbrkr, andbmqtoolabout this field, so they can identify themselves.Please see commit messages for additional details.