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 for OTP 21.3+. #253

Closed
wants to merge 1 commit into from
Closed

Fix for OTP 21.3+. #253

wants to merge 1 commit into from

Conversation

burnison
Copy link

As of 6168cf2 in OTP 21.3, TLS/SSL sockets are active over top of
the TCP sockets. For example, when a SSL socket is in passive mode,
running an :inet.getopts(tls_socket, [:active]) will show something
like [active,96], where-in 96 refers to the fourth packet received,
starting at 100 (the default).

However, Mariaex was originally written before this active,N
implementation. As such, changing the TCP socket into active,once
mode behaved "as expected". To my best understanding, Mariaex does this
in order to "flush" the state buffers. Of course, with the active,N
behaviour of SSL, once Mariaex puts the TCP socket into active,once,
after the next message delivery, the SSL socket becomes passive. This
seemed to create a situation where no further SSL data was made
available.

This change attempts to remove the transition into active,once and,
instead, tries to keep the socket passive at all times to fix #249.

As of `[6168cf2]` in OTP 21.3, TLS/SSL sockets are active over top of
the TCP sockets. For example, when a SSL socket is in passive mode,
running an `:inet.getopts(tls_socket, [:active])` will show something
like `[active,96]`, where-in `96` refers to the fourth packet received,
starting at `100` (the default).

However, Mariaex was originally written before this `active,N`
implementation.  As such, changing the TCP socket into `active,once`
mode behaved "as expected". To my best understanding, Mariaex does this
in order to "flush" the state buffers. Of course, with the `active,N`
behaviour of SSL, once Mariaex puts the TCP socket into `active,once`,
after the next message delivery, the SSL socket becomes passive. This
seemed to create a situation where no further SSL data was made
available.

This change attempts to remove the transition into `active,once` and,
instead, tries to keep the socket passive at all times.

[6168cf2]: erlang/otp@6168cf2
def tag(), do: :ssl

def fake_message(sock, buffer), do: {:ssl, sock, buffer}
Copy link
Author

Choose a reason for hiding this comment

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

My understanding here was that this was used to "flush" out anything that was currently in the socket buffer. Because that code path is gone, I do not believe there is any further use for this.

@@ -240,7 +240,7 @@ defmodule Mariaex.Protocol do
{:error, error, _} ->
{:error, error}
{:ok, _, _, state} ->
activate(state, state.buffer) |> connected()
{:ok, %{state | buffer: state.buffer, state: :running}}
Copy link
Author

Choose a reason for hiding this comment

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

I believe this change has the same semantics as the original code.

sock_mod.close(sock)
end
_ = sock_mod.recv_active(sock, 0, "")
sock_mod.close(sock)
Copy link
Author

Choose a reason for hiding this comment

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

This started to cause some troubles because there was no good way of knowing if disconnect is being called before or after the socket itself was actually closed. This created a difficult-to-debug situation where "left-over" data was stuck in the socket that the message decoder couldn't decode.

Then again, because the original code always closed the socket regardless of the actual response, it seems unnecessary to do the read, anyways.

:ok -> sock_mod.recv_active(sock, 0, "") |> handle_recv_buffer(s)
{:disconnect, _, _} = dis -> dis
def checkout(%{sock: {sock_mod, sock}} = s) do
case sock_mod.recv(sock, 0, 0) do
Copy link
Author

Choose a reason for hiding this comment

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

This was somewhat inspired by the original receive_active code path. I'm not positive it maintains the same semantics, though, as I was never able to reproduce anything except a {:error, :timeout}. I considered just skipping this phase and returning {:ok, %{s | buffer:<<>>}}, but on the slim chance that there is data sitting in the socket, it seems worth clearing out.

@@ -38,10 +38,14 @@ defmodule StartTest do
backoff_type: :stop]

Process.flag :trap_exit, true
assert {:error, {%Mariaex.Error{message: "failed to upgraded socket: {:tls_alert, 'unknown ca'}"}, _}} =
Copy link
Author

Choose a reason for hiding this comment

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

The original tests didn't work properly for me. I suspect this was a result of the original SSL tests always being skipped, possibly having broken in the past. If I'm mistaken, this may come down to a MySQL error message inconsistency between releases.

@coveralls
Copy link

Coverage Status

Coverage increased (+2.2%) to 85.714% when pulling 402b2e8 on PagerDuty:work_with_erlang_21_3 into 5f4aa50 on xerions:master.

3 similar comments
@coveralls
Copy link

Coverage Status

Coverage increased (+2.2%) to 85.714% when pulling 402b2e8 on PagerDuty:work_with_erlang_21_3 into 5f4aa50 on xerions:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+2.2%) to 85.714% when pulling 402b2e8 on PagerDuty:work_with_erlang_21_3 into 5f4aa50 on xerions:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+2.2%) to 85.714% when pulling 402b2e8 on PagerDuty:work_with_erlang_21_3 into 5f4aa50 on xerions:master.

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.

ssl recv timeout on mysql/percona 5.7 connection with TLS enabled
2 participants