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

Fix bugs in idle timeout logic (C#) #3156

Merged
merged 2 commits into from
Nov 16, 2024

Conversation

bernardnormier
Copy link
Member

This PR fixes two small bugs in the idle timeout logic (in C# - will port to other languages in a follow-up PR).


if (op == SocketOperation.None) // connected
{
rescheduleWriteTimer();
Copy link
Member Author

Choose a reason for hiding this comment

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

Bug 1:
Scheduling the first "send heartbeat" in initialize is too early for a client connection that waits for a while to get the ValidateConnection message from the server. We can end up in the situation where the client connection sends its first heartbeat while the Connection is not Active yet, and all the send heartbeats are then lost if the client doesn't write anything else.

@@ -126,7 +117,10 @@ internal IdleTimeoutTransceiverDecorator(Transceiver decoratee, ConnectionI conn

internal void enableIdleCheck()
{
if (!idleCheckEnabled && _readTimer is not null)
// idleCheckEnabled is already true when enableIdleCheck() is called on a TCP server connection that becomes
Copy link
Member Author

Choose a reason for hiding this comment

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

Bug 2:
we can't count on a connection to read anything to schedule the very first idle check.

For example, a TCP server connection can become active and not read anything ever. This should trigger an idle timeout.

Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this second fix.

Copy link
Member Author

Choose a reason for hiding this comment

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

Take a TCP server connection, where the client doesn't send any request or ValidateConnection frame. Maybe because it's not an Ice client.

In this case, when do we schedule the very fist idle check? Can't be in a read since we don't read anything. A good spot is when the ConnectionI becomes active for the first time and calls enableIdleCheck.

Copy link
Member

Choose a reason for hiding this comment

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

but why is idleCheckEnabled already true?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's set to true by the IdleTimeoutTransceiverDecorator constructor.

Maybe a better fix would be to set it to false in the constructor, and rely on the first enableIdleCheck() (from the first activate) to flip it to true?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed as suggested: the constructor no longer sets idleCheckEnabled to true.

@@ -1941,6 +1941,9 @@ private bool validate(int operation)
throw new MarshalException($"Received ValidateConnection message with unexpected size {size}.");
}
TraceUtil.traceRecv(_readStream, this, _logger, _traceLevels);

// Client connection starts sending heartbeats once it's received the ValidateConnection message.
_idleTimeoutTransceiver?.scheduleHeartbeat();
Copy link
Member

Choose a reason for hiding this comment

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

Can _idleTimeoutTransceiver ever be null here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it's null when the idle timeout is <=0 (i.e., disabled)

if (options.idleTimeout > TimeSpan.Zero && !endpoint.datagram())

@@ -1941,6 +1941,9 @@ private bool validate(int operation)
throw new MarshalException($"Received ValidateConnection message with unexpected size {size}.");
}
TraceUtil.traceRecv(_readStream, this, _logger, _traceLevels);

// Client connection starts sending heartbeats once it's received the ValidateConnection message.
Copy link
Member Author

Choose a reason for hiding this comment

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

even if it doesn't write anything (a rare situation).

On the server side, the writing of the initial ValidateConnection message schedules the first heartbeat.

@bernardnormier bernardnormier merged commit 017cbd9 into zeroc-ice:main Nov 16, 2024
19 checks passed
@bernardnormier bernardnormier deleted the idletimeout-fixes branch December 9, 2024 17:10
InsertCreativityHere pushed a commit to InsertCreativityHere/compiler-comparison that referenced this pull request Jan 1, 2025
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.

3 participants