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: stun and dtls close #22

Merged
merged 4 commits into from
Aug 30, 2024
Merged

fix: stun and dtls close #22

merged 4 commits into from
Aug 30, 2024

Conversation

lchenut
Copy link
Collaborator

@lchenut lchenut commented Aug 29, 2024

Description

Working on SCTP made me aware of one issue which raised another one:

  1. When we close a SCTP Connection, the associated DTLS and Stun connections should be closed aswell.
  2. By fixing this issue, I realized that StunConn were not properly closed when created using connect (it was not flushed from Stun.connections Table)

I fixed those two issues and did a quick rework on how Connections are removed from Table.
Before, a Future was created where I awaited for the end of a connection (using await conn.join()) then removed.
Now, join is removed, I replaced it by an onClose sequence of procedure to be called at the end of closing. It solves another potential issue (a race condition) because while awaiting the future to remove the connection from the Table, you could, in theory, re-create the Connection before it's removed, creating a conflict.

As a sweet bonus, I removed one asyncSpawn

The two issues in detail

  • The first issue is a design issue.

When an SCTP Connection is closed, the associated DTLS Connection become useless, it must be closed (so I must call await self.conn.close() when closing an SctpConn).
Similarly, when a DTLS Connection is closed, the associated Stun Connection become useless, it must be closed.
I fixed the DTLS one here https://github.com/vacp2p/nim-webrtc/pull/22/files#diff-33ff420ddc6f5b3b2a85d5b5b37dd7947486d2566811812f1183b721dc436852R223
I'm still working on the SCTP on a separated PR (#11), but I will fix it soon here aswell.

  • The second issue is clearly a bug.

When a StunConn is closed, it should be removed from the Stun.connections table which tracks every connections (in order to close them when the StunTransport is stopped).
Everything works fine when a StunConn is accepted (by calling this asyncSpawn https://github.com/vacp2p/nim-webrtc/pull/22/files#diff-634beab93d219ce578020802e038549117aa731afb0eec174477abd09a3d3dddL76)
But when connecting to a new connection I forgot to start the cleanup.
The consequence of this is that a connected StunConn is effectively "closed" if you check the flag but it is still stored in Stun.connections, thus, when trying to re-connect to this specific address, it will return the already closed StunConn instead of creating a new one. https://github.com/vacp2p/nim-webrtc/pull/22/files#diff-634beab93d219ce578020802e038549117aa731afb0eec174477abd09a3d3dddL51-L52

dtls2 = Dtls.new(stun2)
var
conn1Fut = dtls1.accept()
conn2 = await dtls2.connect(localAddr1)
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe better to use names like client and server?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

@@ -227,7 +229,9 @@ proc close*(self: StunConn) {.async: (raises: []).} =
debug "Try to close an already closed StunConn"
return
await self.handlesFut.cancelAndWait()
self.closeEvent.fire()
for onCloseProc in self.onClose:
onCloseProc()
Copy link
Contributor

Choose a reason for hiding this comment

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

you can pass the conn as param.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't know if it's a good idea, the conn is useless at this point (because it's closed)

proc cleanup() =
self.connections.del(conn.raddr)
self.connections[conn.raddr] = conn
conn.addOnClose(cleanup)
Copy link
Contributor

Choose a reason for hiding this comment

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

Then cleanup doesn't need to be a closure and can be passed when the conn is created. addConnToTable won't be necessary.

@@ -28,6 +28,7 @@ type
StunUsernameProvider* = proc(): string {.raises: [], gcsafe.}
StunUsernameChecker* = proc(username: seq[byte]): bool {.raises: [], gcsafe.}
StunPasswordProvider* = proc(username: seq[byte]): seq[byte] {.raises: [], gcsafe.}
StunConnOnClose* = proc() {.raises: [], gcsafe.}
Copy link
Contributor

Choose a reason for hiding this comment

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

It can be only OnClose, it is clear from the context it is related to a Stun conn.

@lchenut lchenut merged commit 26cad2a into master Aug 30, 2024
8 checks passed
@lchenut lchenut deleted the fix-stun-connect branch August 30, 2024 10:19
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