Skip to content

Commit

Permalink
Merge pull request #1155 from kiyonlin/network-stack
Browse files Browse the repository at this point in the history
🔥 Add network option
  • Loading branch information
kiyonlin authored Feb 8, 2021
2 parents 3e2dd90 + 00dbdd5 commit b32c4fa
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 24 deletions.
21 changes: 15 additions & 6 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@ type Config struct {
// Allowing for flexibility in using another json library for encoding
// Default: json.Marshal
JSONEncoder utils.JSONMarshal `json:"-"`

// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)
// WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chose.
//
// Default: NetworkTCP4
Network string
}

// Static defines configuration options when defining static assets.
Expand Down Expand Up @@ -396,6 +402,9 @@ func New(config ...Config) *App {
if app.config.JSONEncoder == nil {
app.config.JSONEncoder = json.Marshal
}
if app.config.Network == "" {
app.config.Network = NetworkTCP4
}

// Init app
app.init()
Expand Down Expand Up @@ -553,8 +562,8 @@ func NewError(code int, message ...string) *Error {
func (app *App) Listener(ln net.Listener) error {
// Prefork is supported for custom listeners
if app.config.Prefork {
addr, tls := lnMetadata(ln)
return app.prefork(addr, tls)
addr, tlsConfig := lnMetadata(app.config.Network, ln)
return app.prefork(app.config.Network, addr, tlsConfig)
}
// prepare the server for the start
app.startupProcess()
Expand All @@ -573,10 +582,10 @@ func (app *App) Listener(ln net.Listener) error {
func (app *App) Listen(addr string) error {
// Start prefork
if app.config.Prefork {
return app.prefork(addr, nil)
return app.prefork(app.config.Network, addr, nil)
}
// Setup listener
ln, err := net.Listen("tcp4", addr)
ln, err := net.Listen(app.config.Network, addr)
if err != nil {
return err
}
Expand Down Expand Up @@ -613,10 +622,10 @@ func (app *App) ListenTLS(addr, certFile, keyFile string) error {
cert,
},
}
return app.prefork(addr, config)
return app.prefork(app.config.Network, addr, config)
}
// Setup listener
ln, err := net.Listen("tcp4", addr)
ln, err := net.Listen(app.config.Network, addr)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ func Test_App_Listener_TLS(t *testing.T) {
}
config := &tls.Config{Certificates: []tls.Certificate{cer}}

ln, err := net.Listen("tcp4", ":3078")
ln, err := net.Listen(NetworkTCP4, ":3078")
utils.AssertEqual(t, nil, err)

ln = tls.NewListener(ln, config)
Expand Down Expand Up @@ -1151,7 +1151,7 @@ func Test_App_ReadTimeout(t *testing.T) {
go func() {
time.Sleep(500 * time.Millisecond)

conn, err := net.Dial("tcp4", "127.0.0.1:4004")
conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4004")
utils.AssertEqual(t, nil, err)
defer conn.Close()

Expand Down Expand Up @@ -1183,7 +1183,7 @@ func Test_App_BadRequest(t *testing.T) {

go func() {
time.Sleep(500 * time.Millisecond)
conn, err := net.Dial("tcp4", "127.0.0.1:4005")
conn, err := net.Dial(NetworkTCP4, "127.0.0.1:4005")
utils.AssertEqual(t, nil, err)
defer conn.Close()

Expand Down
11 changes: 9 additions & 2 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

/* #nosec */
// lnMetadata will close the listener and return the addr and tls config
func lnMetadata(ln net.Listener) (addr string, cfg *tls.Config) {
func lnMetadata(network string, ln net.Listener) (addr string, cfg *tls.Config) {
// Get addr
addr = ln.Addr().String()

Expand All @@ -37,7 +37,7 @@ func lnMetadata(ln net.Listener) (addr string, cfg *tls.Config) {
// Wait for the listener to be closed
var closed bool
for i := 0; i < 10; i++ {
conn, err := net.DialTimeout("tcp4", addr, 3*time.Second)
conn, err := net.DialTimeout(network, addr, 3*time.Second)
if err != nil || conn == nil {
closed = true
break
Expand Down Expand Up @@ -670,3 +670,10 @@ const (
HeaderXRobotsTag = "X-Robots-Tag"
HeaderXUACompatible = "X-UA-Compatible"
)

// Network types that are commonly used
const (
NetworkTCP = "tcp"
NetworkTCP4 = "tcp4"
NetworkTCP6 = "tcp6"
)
12 changes: 6 additions & 6 deletions helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,23 +262,23 @@ func Benchmark_Utils_IsNoCache(b *testing.B) {

func Test_Utils_lnMetadata(t *testing.T) {
t.Run("closed listen", func(t *testing.T) {
ln, err := net.Listen("tcp", ":0")
ln, err := net.Listen(NetworkTCP, ":0")
utils.AssertEqual(t, nil, err)

utils.AssertEqual(t, nil, ln.Close())

addr, config := lnMetadata(ln)
addr, config := lnMetadata(NetworkTCP, ln)

utils.AssertEqual(t, ln.Addr().String(), addr)
utils.AssertEqual(t, true, config == nil)
})

t.Run("non tls", func(t *testing.T) {
ln, err := net.Listen("tcp", ":0")
ln, err := net.Listen(NetworkTCP, ":0")

utils.AssertEqual(t, nil, err)

addr, config := lnMetadata(ln)
addr, config := lnMetadata(NetworkTCP4, ln)

utils.AssertEqual(t, ln.Addr().String(), addr)
utils.AssertEqual(t, true, config == nil)
Expand All @@ -290,12 +290,12 @@ func Test_Utils_lnMetadata(t *testing.T) {

config := &tls.Config{Certificates: []tls.Certificate{cer}}

ln, err := net.Listen("tcp4", ":0")
ln, err := net.Listen(NetworkTCP4, ":0")
utils.AssertEqual(t, nil, err)

ln = tls.NewListener(ln, config)

addr, config := lnMetadata(ln)
addr, config := lnMetadata(NetworkTCP4, ln)

utils.AssertEqual(t, ln.Addr().String(), addr)
utils.AssertEqual(t, true, config != nil)
Expand Down
4 changes: 2 additions & 2 deletions prefork.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func IsChild() bool {
}

// prefork manages child processes to make use of the OS REUSEPORT or REUSEADDR feature
func (app *App) prefork(addr string, tlsConfig *tls.Config) (err error) {
func (app *App) prefork(network, addr string, tlsConfig *tls.Config) (err error) {
// 👶 child process 👶
if IsChild() {
// use 1 cpu core per child process
runtime.GOMAXPROCS(1)
var ln net.Listener
// Linux will use SO_REUSEPORT and Windows falls back to SO_REUSEADDR
// Only tcp4 or tcp6 is supported when preforking, both are not supported
if ln, err = reuseport.Listen("tcp4", addr); err != nil {
if ln, err = reuseport.Listen(network, addr); err != nil {
if !app.config.DisableStartupMessage {
time.Sleep(100 * time.Millisecond) // avoid colliding with startup message
}
Expand Down
10 changes: 5 additions & 5 deletions prefork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ func Test_App_Prefork_Child_Process(t *testing.T) {

app := New()

err := app.prefork("invalid", nil)
err := app.prefork(NetworkTCP4, "invalid", nil)
utils.AssertEqual(t, false, err == nil)

go func() {
time.Sleep(1000 * time.Millisecond)
utils.AssertEqual(t, nil, app.Shutdown())
}()

utils.AssertEqual(t, nil, app.prefork("[::]:", nil))
utils.AssertEqual(t, nil, app.prefork(NetworkTCP6, "[::]:", nil))

// Create tls certificate
cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key")
Expand All @@ -45,7 +45,7 @@ func Test_App_Prefork_Child_Process(t *testing.T) {
utils.AssertEqual(t, nil, app.Shutdown())
}()

utils.AssertEqual(t, nil, app.prefork("127.0.0.1:", config))
utils.AssertEqual(t, nil, app.prefork(NetworkTCP4, "127.0.0.1:", config))
}

func Test_App_Prefork_Master_Process(t *testing.T) {
Expand All @@ -59,11 +59,11 @@ func Test_App_Prefork_Master_Process(t *testing.T) {
utils.AssertEqual(t, nil, app.Shutdown())
}()

utils.AssertEqual(t, nil, app.prefork(":3000", nil))
utils.AssertEqual(t, nil, app.prefork(NetworkTCP4, ":3000", nil))

dummyChildCmd = "invalid"

err := app.prefork("127.0.0.1:", nil)
err := app.prefork(NetworkTCP4, "127.0.0.1:", nil)
utils.AssertEqual(t, false, err == nil)
}

Expand Down

0 comments on commit b32c4fa

Please sign in to comment.