flomesh-io / pipy

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

reuse-port option not work? #187

Closed yyk808 closed 1 week ago

yyk808 commented 1 week ago

Edit

After reading source code in connect.cpp and listener.cpp, I found that the option --reuse-port is only set for Listener sockets. When the connect filter try to bind the same address without this option, the kernel would refuse. Well, needless to say, this is a corner case indeed. However I DO need this to do something.

I'm trying to implement NAT traversal in pure PJS, which need to take full control of socket, so that I can cheat the firewall and punch a hole through NAT. Using a specific pair to send something then open a server on it is one of the fundamental step. ( For more information about NAT traversal, go check this!)

So I reopen this issue and expecting someone can help.

Issue

First I have a tcp server running on port 8080. And then I wrote some code in test.js

// filename: test.js
pipy().listen('127.0.0.1:1234').dump()
    .task()
    .onStart(new Message('client'))
    .connect('127.0.0.1:8080', {bind:"127.0.0.1:1234"}) // this is line 57 in file.

Run it with option --reuse-port:

❯ pipy test.js --reuse-port
  2024-06-18 13:33:42.611 [INF] [config]
  2024-06-18 13:33:42.611 [INF] [config] Module /test.js
  2024-06-18 13:33:42.611 [INF] [config] ===============
  2024-06-18 13:33:42.611 [INF] [config]
  2024-06-18 13:33:42.611 [INF] [config]  [Listen on 1234 at 127.0.0.1]
  2024-06-18 13:33:42.611 [INF] [config]  ----->|
  2024-06-18 13:33:42.611 [INF] [config]        |
  2024-06-18 13:33:42.611 [INF] [config]       dump -->|
  2024-06-18 13:33:42.611 [INF] [config]               |
  2024-06-18 13:33:42.611 [INF] [config]  <------------|
  2024-06-18 13:33:42.611 [INF] [config]  
  2024-06-18 13:33:42.611 [INF] [config]  [Task #1 ()]
  2024-06-18 13:33:42.611 [INF] [config]  ----->|
  2024-06-18 13:33:42.611 [INF] [config]        |
  2024-06-18 13:33:42.611 [INF] [config]       connect -->|
  2024-06-18 13:33:42.611 [INF] [config]                  |
  2024-06-18 13:33:42.611 [INF] [config]  <---------------|
  2024-06-18 13:33:42.611 [INF] [config]  
  2024-06-18 13:33:42.611 [INF] [listener] Listening on TCP port 1234 at 127.0.0.1
  2024-06-18 13:33:42.611 [ERR] connect() at line 57 column 10 in /test.js: bind: Address already in use
  2024-06-18 13:33:42.611 [ERR] connect() at line 57 column 10 in /test.js: bind: Address already in use
  2024-06-18 13:33:42.611 [ERR] connect() at line 57 column 10 in /test.js: bind: Address already in use

I wonder if it's the right way to use --reuse-port, but I do need a way to use the same port for both inbound and outbound connections in the same time.

Furthermore, I'm expecting a feature in connect or listen like:

pipy().listen(xxx, {reusePort: true })
pipy().task().onStart(new Message()).connect(xxx, {reusePort: ture})

So the socket option can be separately set.

pajama-coder commented 1 week ago

The option --reuse-port corresponds to SO_REUSE_PORT socket option, which is only meaningful for a listening socket. But I'll look to provide a way to change socket options before binding/connecting a client-side socket, if that could be helpful in your case.

pajama-coder commented 1 week ago

@yyk808 In the latest commit cae19357ed6c73e623653e4c50ea3acb0d6bb3ed a new state 'open' is added to connect() filter's callback, where you can do setsockopt() right after a socket is open and before anything else, like:

var SOL_SOCKET = 1
var SO_REUSEPORT = 15

pipeline($=>$
  .connect('x.x.x.x:nnn', {
    onState: inb => {
      if (inb.state === 'open') {
        inb.socket.setRawOption(SOL_SOCKET, SO_REUSEPORT, new Data([1]))
      }
    }
  })
)
pajama-coder commented 1 week ago

@yyk808 The last change for adding an 'open' state to an Outbound had a bug that caused a crash. The issue was just fixed in commit d36b333d910ed6886e89b1c105924fec344ebec8. You'll probably need an update as you use the onState callback.

yyk808 commented 1 week ago

@yyk808 The last change for adding an 'open' state to an Outbound had a bug that caused a crash. The issue was just fixed in commit d36b333. You'll probably need an update as you use the onState callback.

Thank you very much! This helps a lot.