flomesh-io / pipy

Pipy is a programmable proxy for the cloud, edge and IoT.
https://flomesh.io/pipy
Other
775 stars 73 forks source link

[filter] manually bound `connect` doesn't close tcp socket cleanly. #185

Closed yyk808 closed 5 months ago

yyk808 commented 5 months ago

Env

The newest nightly build of pipy on Archlinux.

❯ pipy -v
  Version          : nightly-202406162205
  Commit           : 159d4e82db0367fc138f2427503dfc8ba62dde22
  Commit Date      : Sun, 16 Jun 2024 11:12:56 +0800
  Host             : Linux-6.9.4-zen1-1-zen x86_64
  OpenSSL          : OpenSSL 3.2.0 23 Nov 2023
  Builtin GUI      : Yes
  Builtin Codebases: Yes

Reproduce

First, start a tcp server. Here I use a brief pjs to make it.

pipy -e 'pipy().listen(8080)'

Then, connect to this port with a bound address. Here I use idleTimeout to speed up this reproduction.

❯ pipy -e 'pipy().task().onStart(new Data).connect("127.0.0.1:8080", {bind: "127.0.0.1:1235", idleTimeout: 1}).dump()'
2024-06-17 09:53:28.059 [INF] [config]
2024-06-17 09:53:28.059 [INF] [config] Module 
2024-06-17 09:53:28.059 [INF] [config] =======
2024-06-17 09:53:28.059 [INF] [config]
2024-06-17 09:53:28.059 [INF] [config]  [Task #1 ()]
2024-06-17 09:53:28.059 [INF] [config]  ----->|
2024-06-17 09:53:28.059 [INF] [config]        |
2024-06-17 09:53:28.059 [INF] [config]       connect
2024-06-17 09:53:28.059 [INF] [config]       dump -->|
2024-06-17 09:53:28.059 [INF] [config]               |
2024-06-17 09:53:28.059 [INF] [config]  <------------|
2024-06-17 09:53:28.059 [INF] [config]  
2024-06-17 09:53:29.060 [INF] [dump] [worker=0] [context=2] [ 1:105] StreamEnd, code = IdleTimeout

At the first time we run it, the program will exit as expected. But if we instantly run it again, it says:

❯ pipy -e 'pipy().task().onStart(new Data).connect("127.0.0.1:8080", {bind: "127.0.0.1:1235", idleTimeout: 1}).dump()'
2024-06-17 09:53:30.099 [INF] [config]
2024-06-17 09:53:30.099 [INF] [config] Module 
2024-06-17 09:53:30.099 [INF] [config] =======
2024-06-17 09:53:30.099 [INF] [config]
2024-06-17 09:53:30.099 [INF] [config]  [Task #1 ()]
2024-06-17 09:53:30.099 [INF] [config]  ----->|
2024-06-17 09:53:30.099 [INF] [config]        |
2024-06-17 09:53:30.099 [INF] [config]       connect
2024-06-17 09:53:30.099 [INF] [config]       dump -->|
2024-06-17 09:53:30.099 [INF] [config]               |
2024-06-17 09:53:30.099 [INF] [config]  <------------|
2024-06-17 09:53:30.099 [INF] [config]  
2024-06-17 09:53:30.100 [ERR] connect() at line 1 column 40: bind: Address already in use
2024-06-17 09:53:30.100 [INF] [dump] [worker=0] [context=2] [ 1:105] StreamEnd, code = RuntimeError, error = { name: "Error", message: "connect() at line 1 column 40: bind: Address already in use", cause: null, stack: undefined }

If not set the bind option, everything works fine.

Plus, from the packets cap by wireshark, the program indeed disconnected gracefully. 图片

nixff commented 5 months ago

I think the system need some time to release the local port 1235. If you rerun the task pipeline instantly, the port is still in time-wait state.

you could try ss -an | grep 1235

yyk808 commented 5 months ago

@nixff Yes, you are right. I didn't realize there is a time-wait state for tcp sockets. I'll close this issue soon.