Repository: fatedier/frp (language: go)

Issue:
all quic traffic from frpc to frps stalls
### Bug Description

The new quic support is great! For static file downloads I was able to increase throughput from 4MB/s to around 13MB/s simply by switching to the new `protocol = quic`. Unfortunately my excitement was short lived as the tunnel would stop working entirely when I started trying to seek around a video served through the frp tunnel from my Jellyfin media server. Restarting the tunnel would always fix the problem until you seek on the video again a few times. A minimal repro can be made by simply opening a tunnel to a local http server which is serves a video file and dragging the playhead in the browser to generate a bunch of requests:

https://user-images.githubusercontent.com/18545667/211148931-63a3056d-a2d7-43bb-b86c-1446f396971f.mp4

It seems to vary how many times you can seek around the video, some times only once would cause the tunnel to break, others maybe 10 or more times. I have found dragging the playhead around the video will guarantee to trigger the issue.

I have spent a couple days now wrapping my head around the codebase and learning go to try and understand where the issue was occurring. Today I found a hacky solution that solves the video seeking issue at least temporarily.

```diff
index fc59b39..6570323 100644
--- a/server/service.go
+++ b/server/service.go
@@ -218,6 +218,13 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
                        MaxIdleTimeout:     time.Duration(cfg.QUICMaxIdleTimeout) * time.Second,
                        MaxIncomingStreams: int64(cfg.QUICMaxIncomingStreams),
                        KeepAlivePeriod:    time.Duration(cfg.QUICKeepalivePeriod) * time.Second,
+                       // I believe the key thing is the initial connection receive window
+                       MaxConnectionReceiveWindow:     1e+8,      // 100MB
+                       InitialConnectionReceiveWindow: 1e+8,
+                       MaxStreamReceiveWindow:         1e+8 / 50, // Was just testing different settings here, don't think there is anything specific about the /50 that makes this work vs just using e.g. 15MB but I assume this needs to be LESS than MaxConnectionReceiveWindow as I believe the core problem is that the connection receive window allowance is exhausted by unclosed streams or something thus preventing any more data from being sent
+                       InitialStreamReceiveWindow:     128,       // On an individual stream start the receive window tiny
                })
                if err != nil {
                        err = fmt.Errorf("listen on quic udp address %s error: %v", address, err)
```

With this change in place the quic connection no longer breaks down **BUT** both frpc and frps memory usage continues increasing as I drag the playhead around the video (after doing so for about 30s I observed ~50MB memory usage on windows), I would assume indicating that there are a bunch of quic streams that are not being closed or something.

### frpc Version

1.46.0

### frps Version

1.46.0

### System Architecture

Observed on linux/amd64, windows/x86_64, linux_arm64, darwin

### Configurations

frpc.ini
```
[common]
server_addr = localhost
server_port = 7000
protocol = quic
log_level = debug

[tcp-service]
type = tcp
local_ip = localhost
local_port = 3000
remote_port = 8080
```

frps.ini
```
[common]
bind_port = 7000
quic_bind_port = 7000
log_level = debug
```

### Logs

[frpc.log](https://github.com/fatedier/frp/files/10366135/frpc.log)
[frps.log](https://github.com/fatedier/frp/files/10366136/frps.log)


### Steps to reproduce

- Run a frps with a quic port and have frpc connect opening a tunnel for tcp traffic to an application serving a video file
- Access and attempt to seek a few times within the video file served over the tunnel
- Observe eventually frpc traffic is no longer being transmitted back to frps. Frps receives the requests from the browser, and frpc even gets the ReqWorkConn messages, but no StreamFrames are transmitted back from frpc to frps anymore

### Affected area

- [ ] Docs
- [ ] Installation
- [X] Performance and Scalability
- [ ] Security
- [X] User Experience
- [ ] Test and Release
- [ ] Developer Infrastructure
- [X] Client Plugin
- [ ] Server Plugin
- [ ] Extensions
- [ ] Others


Discussion / hints:
@delaneyb Thanks for your feedback and your detail infos. It helps me a lot.

I find that the bug maybe caused by `Close()` of quic stream. Releated issue https://github.com/lucas-clemente/quic-go/issues/3558

We need to call `CancelRead()` too. I will fix it soon.

Fix patch:
diff --git a/pkg/util/net/conn.go b/pkg/util/net/conn.go
index 1258ed48063..a09da99e702 100644
--- a/pkg/util/net/conn.go
+++ b/pkg/util/net/conn.go
@@ -211,3 +211,8 @@ func (conn *wrapQuicStream) RemoteAddr() net.Addr {
 	}
 	return (*net.TCPAddr)(nil)
 }
+
+func (conn *wrapQuicStream) Close() error {
+	conn.Stream.CancelRead(0)
+	return conn.Stream.Close()
+}


Test patch: