Skip to content

multiplexer: don't fail if Close() is called concurrently to Read(), Write()#632

Merged
djs55 merged 2 commits intomoby:masterfrom
djs55:close-window
Apr 11, 2023
Merged

multiplexer: don't fail if Close() is called concurrently to Read(), Write()#632
djs55 merged 2 commits intomoby:masterfrom
djs55:close-window

Conversation

@djs55
Copy link
Copy Markdown
Collaborator

@djs55 djs55 commented Apr 4, 2023

It's legal for a single net.Conn to be shared between goroutines, for example calling Close() on <- ctx.Done() while calls are blocked in Read and Write.

The multiplexer does not impose an ordering in send: each concurrent call simply competes for the writeMutex.

Therefore sequences we considered invalid are actually possible:

  • Close(id) then Window(id)
  • Close(id) then Write(id)
  • Close(id) then Shutdown(id)

Previously we detected these invalid sequences and shutdown the whole multiplexer. The effect would be to completely disable port forwarding.

Instead we drop these out-of-order packets and log (just in case it's interesting). There is a very small risk that an old out-of-order packet could be mixed up with a new packet if the channel ID is reused, but we have a space of 2**32 of those so re-use is unlikely.

djs55 added 2 commits April 4, 2023 10:11
Instead send the errors back to the main goroutine.

Signed-off-by: David Scott <dave@recoil.org>
A test run demonstrated a two-way Close
```
[2023-04-04T05:48:03.965050200Z][com.docker.backend.exe][I] recv  3 Close
[2023-04-04T05:48:03.965050200Z][com.docker.backend.exe][I] send  3 Close
```
at this point the channel refcount is 0 and the channel considered closed
```
[2023-04-04T05:48:03.965050200Z][com.docker.backend.exe][I] close 3 -> UDP:127.0.0.1:5201
```
however an in-progress Read call read some buffered data and sent a window advertisement:
```
[2023-04-04T05:48:03.965050200Z][com.docker.backend.exe][I] recv  3 Window 935323206
```
which broke the multiplexer with
```
[2023-04-04T05:48:03.918050500Z][com.docker.backend.exe][I] Multiplexer main loop failed with Unknown channel id 3 Window 935323206
```

Previously it was illegal to send anything after a Close(). However it's legal
for clients to call Close() in goroutines while other goroutines are calling
Read() or Write(). Each send call competes for the writeMutex, which means it's
possible for the messages to be sent out-of-order.

Since we have 2**32 channel numbers there should not be any confusion if we
simply expect the occasional out-of-order packet after a Close and drop it.

Signed-off-by: David Scott <dave@recoil.org>
@djs55 djs55 merged commit 2dc2744 into moby:master Apr 11, 2023
@djs55 djs55 deleted the close-window branch April 11, 2023 07:52
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.

2 participants