go-libp2p icon indicating copy to clipboard operation
go-libp2p copied to clipboard

webrtc: wait for FIN_ACK before closing data channels

Open sukunrt opened this issue 2 years ago • 6 comments

part of #2656

This removes the control message queue because that only ever adds 500 bytes to the queue. This will not cause too much HOL Blocking for other streams.

There is no problem with backpressure since sctp writes never actually block. There is no blocking on sctp Write.

To verify:

func TestStreamBackpressure(t *testing.T) {
	client, _ := getDetachedDataChannels(t)

	clientStr := newStream(client.dc, client.rwc, nil)

	b := make([]byte, 1024)
	for i := 0; i < 1e7; i++ {
		n, err := clientStr.dataChannel.Write(b)
		if n != 1024 {
			t.Fatalf("failed to write to datachannel")
		}
		if err != nil {
			t.Fatalf("failed to write to datachannel")
		}
	}
}

sukunrt avatar Oct 22 '23 20:10 sukunrt

I don't have a good idea on how to ensure that we collect the stream handler goroutine and then close the stream rcmgr scope if the transport stream object is responsible for closing the scope and not the swarm stream object.

However a public interface that exposes AsyncClose doesn't seem required either. I've made the assertion private to swarm package. This is subtle action at a distance but at least it makes it clear that we don't want this AsyncClose system to be copied in other transports.

sukunrt avatar Dec 12 '23 14:12 sukunrt

@Jorropo can you help review this PR?

p-shahi avatar Feb 08 '24 07:02 p-shahi

go-libp2p open maintainers call: We have @guillaumemichel 's approval and pending other review comments we will merge this PR. There are other Pion fixes that are necessary to take WebRTC out of experimental as well but merging this will help get the next v0.33 release out the door

p-shahi avatar Feb 08 '24 16:02 p-shahi

@Stebalien I have removed AsyncClose.

The difference between webrtc and yamux/quic is that you're relying on the transport stack to discard all the buffers when you do a Close. This happens with yamux. With quic, the receive side of the stream is not immediately discarded but the peer doesn't get credits to open a new stream till it cleanly finishes the stream after we have sent STOP_SENDING on.

No such mechanism exists in webrtc. There is no limit to streams you can open(At least not in pion) or unilateral stream closing since streams are reusable. In webrtc datachannel.Close is a 1RTT sync procedure over the FIN / FIN_ACK closing that we do. So an effective AsyncClose procedure needs to do it after the datachannel is Closed and not after a FIN_ACK is received. Moreover pion never drops a reference to the datachannel(including all the transport layer allocated buffers) till the connection is open. So a system like this only makes sense if we fix: https://github.com/pion/webrtc/issues/2672

There is one way to handle this other than doing an explicit async close without waiting for 1RTT which would require us to check a misbehaving peer which is forcing us to keep all the datachannels open and just close the connection to such a peer. We can discuss that strategy in a separate issue. That'd also require https://github.com/pion/webrtc/issues/2672

sukunrt avatar Feb 13 '24 14:02 sukunrt

With quic, the receive side of the stream is not immediately discarded but the peer doesn't get credits to open a new stream till it cleanly finishes the stream after we have sent STOP_SENDING on.

Can't we do the same thing here? My objection is adding this hack to libp2p itself as this is a transport specific detail.

Stebalien avatar Feb 13 '24 15:02 Stebalien

My objection is adding this hack to libp2p itself as this is a transport specific detail.

That's a fair point. I'll open an issue to discuss.

sukunrt avatar Feb 13 '24 16:02 sukunrt

@Stebalien

Why not just call closeAndRemoveStream immediately?

I have addressed this and removed the AsyncClose logic. Is it fine to merge?

sukunrt avatar Feb 19 '24 12:02 sukunrt

I have addressed your concerns here. I want to do a release today. Happy to take any comments in a follow up PR and if something major is missed we can do a patch release.

Nope, LGTM!

Stebalien avatar Feb 21 '24 15:02 Stebalien