Skip to content
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

changed Limiter.requests to AtomicLong #214

Merged

Conversation

yuriykulikov
Copy link
Contributor

This avoids Int overflow when client is misbehaving and is sending multiple RequestN frames with n=Int.MAX_VALUE

Motivation:

This closes #213

Modifications:

Changed AtomicInt to AtomicLong. Overflow is still possible after that, however it will require the client sending a RequestN frame 2147483647 times. Not sure if the request value can become negative under other circumstances. If not, unsigned long can be used instead or the value can be asserted to be positive.

Result:

Server won't hang after receiving RequestN frames anymore.

@olme04
Copy link
Contributor

olme04 commented Mar 3, 2022

Hey, @yuriykulikov thanks for report and PR!
Looking at protocol: https://github.com/rsocket/rsocket/blob/master/Protocol.md#reactive-streams-semantics looks like it's expected behavior to use Long for counter.
But, looking at rsocket-java: https://github.com/rsocket/rsocket-java/blob/37fc68c68f4b61d826084330a7b0476a456b63da/rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameCodec.java#L22 Int.MAX_VALUE is coercing to Long.MAX_VALUE, so by emulating via Int.MAX_VALUE unbounded stream, as stated in reactive-streams spec 3.17 rule here: https://github.com/reactive-streams/reactive-streams-jvm#3.17

So looks like the right fix for making rsocket-kotlin compatible with protocol and other implementations would be:

  1. use Long for counter to avoid overflow, if there will be multiple BIG requests, but not Int.MAX_VALUE
  2. treat Int.MAX_VALUE as Long.MAX_VALUE, and as so make limiter unbounded
    • f.e. by adding unbounded Boolean property and based on it ignore any updateRequests, and any check in useRequest

Will you do this, or I can create PR with proposed changes?
BTW, if you will do this, looks like you can also remove using atomic at all in Limiter - which was needed when using old Native MM, which is not the case now.

@yuriykulikov
Copy link
Contributor Author

Hello @olme04,

This sounds reasonable and was also my first thought. However, I was confused after digging into https://rsocket.io/about/protocol/#flow-control which states: Please note that this explicitly does NOT follow rule number 17. (...) While Reactive Streams support a demand of up to 2^63-1, and treats 2^63-1 as a magic number signaling to not track demand, this is not the case for RSocket. RSocket prioritizes byte size and only uses 4 bytes instead of 8 so the magic number is unavailable..

In the end, both approaches effectively achieve the same.

Will you do this, or I can create PR with proposed changes?

I will be glad to implement the changes as you have suggested.

Let me summarize how I have understand how the Limiter should work:

  • Use Long to prevent overflows
  • Treat anything except Int.MAX_VALUE as normal requests (accumulate)
  • if RequestStream n=Int.MAX_VALUE or RequestN n=Int.MAX_VALUE, switch into unbounded mode
  • remove atomics

@olme04
Copy link
Contributor

olme04 commented Mar 4, 2022

@yuriykulikov yes, it should work like this.
Minor addition is please make sure to not overflow on accumulating by coercing to Long.MAX_VALUE (even if it never happen in well behaved implementation).

This avoids Int overflow when client is misbehaving and is sending multiple RequestN frames with n=Int.MAX_VALUE

This closes rsocket#213
@yuriykulikov yuriykulikov force-pushed the bugfix/server-request-counter-overflow#213 branch from 8e8d79b to b5b37c6 Compare March 29, 2022 14:17
@olme04
Copy link
Contributor

olme04 commented Mar 29, 2022

Hey @yuriykulikov, thx for implementing it!
But we just found an issue with rsocket-java implementation regarding using Int.MAX_VALUE, and looks like current implementation will be further adapted.

TL;DR: the problem is, that Int.MAX_VALUE overall is reasonable request, which doesn't mean, that request is unbounded.
more info here: rsocket/rsocket#325

@yuriykulikov
Copy link
Contributor Author

Hey @olme04, I will adjust my implementation to remove the magic meaning of Int.MAX value. Protection against overflow is still relevant even if the U flag is implemented.

}

@Test
fun testStreamRequestNUnbounded() = test {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test fails, could you check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't run all tests before pushing 🤦. I will push the change as a third commit, but I assume all three will be squashed. Or should I squash myself?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just do third commit
they will be squashed on merge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed the commit :)

@olme04
Copy link
Contributor

olme04 commented Mar 30, 2022

Overall LGTM, but please check test

@olme04
Copy link
Contributor

olme04 commented Mar 30, 2022

@yuriykulikov thx for the contribution! All tests passed!

@whyoleg whyoleg merged commit aa95bd3 into rsocket:master Mar 30, 2022
@yuriykulikov
Copy link
Contributor Author

Glad I could contribute 😊

@yuriykulikov yuriykulikov deleted the bugfix/server-request-counter-overflow#213 branch March 30, 2022 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Server: Request-Stream requests counter can overflow when client is misbehaving
3 participants