Giter VIP home page Giter VIP logo

go-reuseport's People

Contributors

anacrolix avatar chaitanyaprem avatar coderlane avatar cryptix avatar dependabot-preview[bot] avatar fhs avatar jbenet avatar kerwinkoo avatar kevina avatar kubuxu avatar libp2p-mgmt-read-write[bot] avatar magik6k avatar marcopolo avatar marten-seemann avatar raulk avatar stebalien avatar tptee avatar victorb avatar web-flow avatar web3-bot avatar whyrusleeping avatar willscott avatar yusefnapora avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-reuseport's Issues

should I set SO_REUSEADDR in go app

In Go, the net.Listen function automatically sets the SO_REUSEADDR option by default when creating a listening socket. This ensures that the same address can be used by multiple sockets simultaneously, which is often required in server applications.

the source from go

func (fd *netFD) listenStream(laddr sockaddr, backlog int, ctrlFn func(string, string, syscall.RawConn) error) error {
	var err error
	if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
		return err
	}
	var lsa syscall.Sockaddr
	if lsa, err = laddr.sockaddr(fd.family); err != nil {
		return err
	}
	if ctrlFn != nil {
		c, err := newRawConn(fd)
		if err != nil {
			return err
		}
		if err := ctrlFn(fd.ctrlNetwork(), laddr.String(), c); err != nil {
			return err
		}
	}
	if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
		return os.NewSyscallError("bind", err)
	}
	if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
		return os.NewSyscallError("listen", err)
	}
	if err = fd.init(); err != nil {
		return err
	}
	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
	fd.setAddr(fd.addrFunc()(lsa), nil)
	return nil
}


// unix 
func setDefaultListenerSockopts(s int) error {
	// Allow reuse of recently-used addresses.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

func setDefaultMulticastSockopts(s int) error {
	// Allow multicast UDP and raw IP datagram sockets to listen
	// concurrently across multiple listeners.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

Unexpected address type for UDP

Following example returns an error listen udp 127.0.0.1:1234: address 127.0.0.1:1234: unexpected address type:

package main

import (
	"fmt"
	"os"

	"github.com/libp2p/go-reuseport"
)

func main() {
	l, err := reuseport.Listen("udp", "127.0.0.1:1234")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(l)
}

TCP 3 way handshake

How do you work around connection resets during a 3 way handshake if the number of listeners changes?

[Need Help] testing udp receive and send in two debian PCs in my LAN

the test.go:

package main

import (
	"fmt"
	"time"

	reuseport "github.com/libp2p/go-reuseport"
)

func main() {
	go func() {
	// Create a new UDP socket using the reuseport package
	conn, err := reuseport.ListenPacket("udp", "0.0.0.0:15443")
	if err != nil {
		fmt.Println("Error listening:", err)
		return
	}
	defer conn.Close()
	// Continuously read data from the UDP socket and print it to the console
	for {
		buf := make([]byte, 1024)
		n, addr, err := conn.ReadFrom(buf)
		if err != nil {
			fmt.Println("Error reading:", err)
			continue
		}

		fmt.Printf("Received %d bytes from %s: %s\n", n, addr.String(), string(buf[:n]))
	}
	}()

	go func() {
		// Create a new UDP socket using the reuseport package
		conn, err := reuseport.Dial("udp", "0.0.0.0:15443", "192.168.0.1:15443")
		if err != nil {
			fmt.Println("Error connecting:", err)
			return
		}
		defer conn.Close()

		for {
			msg := []byte("Hello, world!")
			_, err := conn.Write(msg)
			if err != nil {
				//fmt.Println("Error sending message:", err)
				continue
			}

			//fmt.Println("Message sent:", string(msg))
			time.Sleep(1 * time.Second) // Wait for 1 second before sending the next message
		}
	}()

	go func() {
		// Create a new UDP socket using the reuseport package
		conn, err := reuseport.Dial("udp", "0.0.0.0:15443", "192.168.0.2:15443")
		if err != nil {
			fmt.Println("Error connecting:", err)
			return
		}
		defer conn.Close()

		for {
			msg := []byte("Hello, world!")
			_, err := conn.Write(msg)
			if err != nil {
				//fmt.Println("Error sending message:", err)
				continue
			}

			//fmt.Println("Message sent:", string(msg))
			time.Sleep(1 * time.Second) // Wait for 1 second before sending the next message
		}
	}()
	time.Sleep(100000 * time.Second)
}

compile the test.go and put it into the 192.168.0.1 and 192.168.0.2, and exec it in the two machines,
but there's no message printed in both of the two machines,
but if i stop one of them and keep the other run,
and run "nc -u -p 15443 192.168.0.1 15443" in the stopped one, I can see many "Hello, world!" printing.

I can't understand why, any hint?

SO_REUSEPORT has gone from unix_impl

Operating system linux

Looks like constant SO_REUSEPORT has gone from linux impl.

libp2p/go-reuseport/impl_unix.go:47:51: undefined: unix.SO_REUSEPORT

Are you planning on adding tfo(tcp fast open)

do you plan to develop a new version of TFO to support golang?It is really excellent to reduce the time of TCP three-time handshake ,but don‘t support golang still now,and golang is a popular computer language in recent years。thanks

win not work

image

i want use nat ,build a connect for two work's net 。 my user most use win .....

Dial fails unless I disable the available() check

First time using the library, I tried doing a Dial() (only, I'm not using Listen()) on linux, x86-64, kernel 4.4.0-92-generic but it returns an error protocol not available from available(). If I comment out the available() check then it seems to work as expected, reusing the port as I wanted.

My code looked like this:

	var d reuse.Dialer
	d.D.Timeout = 5 * time.Second
	d.D.LocalAddr, err = net.ResolveTCPAddr("tcp", "0.0.0.0:"+sourcePort)
	if err != nil {
		return err
	}
	conn, err := d.Dial("tcp", ipAddress+":"+port)
	if err != nil {
		return err
	}
	defer conn.Close()

The constant SO_REUSEPORT is still missing in Linux/386 and amd64.

It's related to #36 and #41 .
I got a compile error when build codes in my linux.
I found related issue in golang official; golang/go#23696

Here is my Ubuntu system. I check go-1.10 and go-1.9.
adm@ubuntu1604:/usr/lib/go-1.10/src$ uname -a
Linux ubuntu1604 4.4.0-128-generic #154-Ubuntu SMP Fri May 25 14:15:18 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

adm@ubuntu1604:/usr/lib/go-1.10/src$ grep -R SO_REUSEPORT * | sort
net/net_test.go: // enabling SO_REUSEPORT option such as Linux,
net/sockopt_bsd.go: return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1))
syscall/net_nacl.go: SO_REUSEPORT
syscall/zerrors_darwin_386.go: SO_REUSEPORT = 0x200
syscall/zerrors_darwin_amd64.go: SO_REUSEPORT = 0x200
syscall/zerrors_darwin_arm64.go: SO_REUSEPORT = 0x200
syscall/zerrors_darwin_arm.go: SO_REUSEPORT = 0x200
syscall/zerrors_dragonfly_amd64.go: SO_REUSEPORT = 0x200
syscall/zerrors_freebsd_386.go: SO_REUSEPORT = 0x200
syscall/zerrors_freebsd_amd64.go: SO_REUSEPORT = 0x200
syscall/zerrors_freebsd_arm.go: SO_REUSEPORT = 0x200
syscall/zerrors_linux_arm64.go: SO_REUSEPORT = 0xf
syscall/zerrors_linux_mips64.go: SO_REUSEPORT = 0x200
syscall/zerrors_linux_mips64le.go: SO_REUSEPORT = 0x200
syscall/zerrors_linux_mips.go: SO_REUSEPORT = 0x200
syscall/zerrors_linux_mipsle.go: SO_REUSEPORT = 0x200
syscall/zerrors_linux_ppc64.go: SO_REUSEPORT = 0xf
syscall/zerrors_linux_ppc64le.go: SO_REUSEPORT = 0xf
syscall/zerrors_linux_s390x.go: SO_REUSEPORT = 0xf
syscall/zerrors_netbsd_386.go: SO_REUSEPORT = 0x200
syscall/zerrors_netbsd_amd64.go: SO_REUSEPORT = 0x200
syscall/zerrors_netbsd_arm.go: SO_REUSEPORT = 0x200
syscall/zerrors_openbsd_386.go: SO_REUSEPORT = 0x200
syscall/zerrors_openbsd_amd64.go: SO_REUSEPORT = 0x200
syscall/zerrors_openbsd_arm.go: SO_REUSEPORT = 0x200

Support Linux on ARM64

The standard Go syscall package doesn't/won't implement EpollWait on ARM64:

EpollWait returned error: function not implemented. Continuing. linux.go:189

The fix should be simple: replace the syscall import with golang.org/x/sys/unix

available_unix.go is over complex

Belated drive-by code review.

It looks like available_unix.go could be replaced with

var (
    hasReusePort bool
    didReusePort sync.Once
)

func checkReusePort() {
    ...
    hasReusePort = whatever
}

func available() bool {
    didReusePort.Do(checkReusePort)
    return hasReusePort
}

compilation fails on NetBSD

compilation

on NetBSD fails with

gx/ipfs/QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ/go-reuseport/poll

../../../../../gx/ipfs/QmaaC9QMYTQHCbMq3Ebr3uMaAR2ev4AVqMmsJpgQijAZbJ/go-reuseport/poll/poll_bsd.go:29: cannot use nil as type int64 in field value
*** Error code 2

poll_bsd.patch.txt

[Question] Not clear implementation of Available()

// Available returns whether or not SO_REUSEPORT or equivalent behaviour is
// available in the OS.
func Available() bool {
	return true
}

So for every os SO_REUSEPORT is available

But for windows (see below) it does not exist

func Control(network, address string, c syscall.RawConn) (err error) {
	controlErr := c.Control(func(fd uintptr) {
		err = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
	})
	if controlErr != nil {
		err = controlErr
	}
	return
}

do you accept PRs?

Build fails on windows as of 0.1.8 release.

Building with CGO_ENABLED=0 GOOS=windows I get the following:

vendor/github.com/libp2p/go-reuseport/interface.go:49: undefined: unix.ENOPROTOOPT
vendor/github.com/libp2p/go-reuseport/interface.go:60: undefined: unix.ENOPROTOOPT
vendor/github.com/libp2p/go-reuseport/interface.go:71: undefined: unix.ENOPROTOOPT
vendor/github.com/libp2p/go-reuseport/interface.go:101: undefined: unix.ENOPROTOOPT

Looks like some unix stuff may be sneaking into the windows build.

SO_REUSEPORT should supersede SO_REUSEADDR

If my understanding is correct, SO_REUSEPORT will be the desired behaviour 99.9% of the time. In control_unix.go, for the following code

                err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
		if err != nil {
			return
		}

		err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
		if err != nil {
			return
		}

instead of setting (or trying to) both options, it should be a try/fail-safe scenario. We should try to set SO_REUSEPORT and if that fails, try to set SO_REUSEADDR. The current approach seems a bit redundant. Imo, it should look something like this,

		if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err == nil { 
			return
		}
                unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)

panic: address already in use

I tried your demo, but still appeared this problem: "address already in use"

go version go1.4.2 linux/amd64
CentOS release 6.6 (Final)
Linux version 2.6.32-504.el6.x86_64

why?

Bug-Report[reuse-port]fail to bind port in some device

in win7 with services VNCServer running on 5900,run following will sometimes get error.

import (
	"fmt"
	"log"
	"net"
	reuseport "github.com/libp2p/go-reuseport"
)

func reuse(options *Options) (net.Conn, string) {
	listenAddr := fmt.Sprintf("%s:%s", options.ReuseHost, options.ReusePort)

	listener, err := reuseport.Listen("tcp", listenAddr)
	if err != nil {
		log.Fatalf("[*] Error occured: %s", err.Error()) // HERE throw error
	}
}

bind: attempt was made to access a socket in a way forbidden by its access permissions
i tested in 2 different devices which one successfully listen and one fail.

reuseport.Listen success on Darwin, but maybe not load balanced

Please check my testcase:
https://github.com/hitzhangjie/codemaster/tree/master/hot_restart

you can go run main.go to run the server, and curl http://localhost:8080/hello to see Hello from $pid.

then kill -SIGUSR1 $pid to notify it do a fork, parent and children processes reuseport.Listen successfully.

but curl always return the same $pid.

Only after I kill -SIGTERM $1st-pid, the 2nd listener works in the forked children process,
then kill the 2nd forked process, then curl you'll see the 3rd forked process works.

Error on ListenPacket with wildcard address (":8080")

When i Listen on ":8080" by udp with reuseport, following error occurs.

$ cat e.go
package main

import (
    "fmt"

    reuse "github.com/jbenet/go-reuseport"
)

func main() {
    _, err := reuse.ListenPacket("udp", ":8080")
    fmt.Println(err)
}

$ go run e.go
address family not supported by protocol

This breaks compatibility with golang's standard net.ListenPacket.

In Golang standard, they are guessing address family from network and wildcard address ( http://golang.org/src/net/ipsock_posix.go#L72)

Enhancement: For FreeBSD based systems, enable connection load balancing in case of multiple listeners.

Enhancement

In linux based systems, setting SO_REUSEPORT socket option and binding multiple listening sockets enables kernel to perform connection load balancing onto all listeners.
Whereas this is not implemented in windows and macOS.

But for FreeBSD based systems, an additional socket option called SO_REUSEPORT_LB has to be enabled in order for this load balancing to take place. It is described here.

Hence, this is an enhancement issue to enable this new option for freeBSD based systems.

Can reuse.Dialer dial to a public address?

It works when addr2 := "127.0.0.1:80"
but not work on addr2 := "www.baidu.com:80" which changing to a public address
outputs is
panic: invalid argument

go version: go1.5.1 linux/amd64

Some code like this:

package main

import (
    "fmt"
    resolve "github.com/jbenet/go-net-resolve-addr"
    reuse "github.com/jbenet/go-reuseport"
    "net"
)

func main() {
    addr0 := "0.0.0.0:8808"
    addr1 := "127.0.0.1:8808"

    //public address
    addr2 := "www.baidu.com:80"

    //127.0.0.1:80 works
    //addr2 := "127.0.0.1:80"

    l1, err := reuse.Listen("tcp", addr0)
    if err != nil {
        panic(err)
    }

    go func() {
        l1to2bar, err := l1.Accept()
        if err == nil {
            fmt.Printf("%s accepted conn from %s\n", addrStr(l1.Addr()), addrStr(l1to2bar.RemoteAddr()))
        } else {
            fmt.Printf(err.Error())
        }
    }()

    a1, err := resolve.ResolveAddr("dial", "tcp", addr1)
    if err != nil {
        panic(err)
    }

    d1 := reuse.Dialer{net.Dialer{LocalAddr: a1}}

    //dial to a public address
    d1to2foo, err := d1.Dial("tcp4", addr2)
    if err != nil {
        panic(err)
    }
    fmt.Printf("conn to %s\n", addrStr(d1to2foo.RemoteAddr()))

    fmt.Println("IT WORKS!")
}

func addrStr(a net.Addr) string {
    return fmt.Sprintf("%s/%s", a.Network(), a)
}

seems to be obviously mistake

on impl_unix.go line:109
if lfamily != rfamily && lprotocol != rfamily {

seems should be
if lfamily != rfamily && lprotocol != rprotocol {

impl_wasm is redeclaring methods

Since d6da3d7, our continuous integration has been failing to go get -t -v ./... our project, which includes a transitive dependency on this project.

https://travis-ci.org/prysmaticlabs/prysm/jobs/475105707

github.com/libp2p/go-reuseport
# github.com/libp2p/go-reuseport
../../libp2p/go-reuseport/impl_wasm.go:10:53: listen redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/impl_unix.go:211:45
../../libp2p/go-reuseport/impl_wasm.go:14:56: listenPacket redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/impl_unix.go:291:61
../../libp2p/go-reuseport/impl_wasm.go:18:53: listenStream redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/impl_unix.go:260:59
../../libp2p/go-reuseport/impl_wasm.go:22:87: dial redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/impl_unix.go:62:87
../../libp2p/go-reuseport/impl_wasm.go:26:18: available redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/available_unix.go:23:18

Control redeclared in this block

When I run this command

go get -u github.com/libp2p/go-reuseport

it returns error:

# github.com/libp2p/go-reuseport
../../libp2p/go-reuseport/control_wasm.go:7:58: Control redeclared in this block
	previous declaration at ../../libp2p/go-reuseport/control_unix.go:11:58
../../libp2p/go-reuseport/interface.go:33:20: undefined: net.ListenConfig
../../libp2p/go-reuseport/interface.go:41:2: not enough arguments to return
../../libp2p/go-reuseport/interface.go:48:2: not enough arguments to return
../../libp2p/go-reuseport/interface.go:60:10: unknown field 'Control' in struct literal of type net.Dialer

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.