diff --git a/HISTORY.md b/HISTORY.md index 6750362d..b184f008 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -371,6 +371,8 @@ Other Improvements: ![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0) +- Socket Sharding as requested at [#1544](https://github.com/kataras/iris/issues/1544). New `iris.WithSocketSharding` Configurator and `SocketSharding bool` setting. + - Versioned Controllers feature through the new `mvc.Version` option. See [_examples/mvc/versioned-controller](https://github.com/kataras/iris/blob/master/_examples/mvc/versioned-controller/main.go). - Fix [#1539](https://github.com/kataras/iris/issues/1539). diff --git a/_examples/README.md b/_examples/README.md index e4cf7d7b..4611ff99 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -15,11 +15,11 @@ * [UNIX socket file](http-server/listen-unix/main.go) * [TLS](http-server/listen-tls/main.go) * [Letsencrypt (Automatic Certifications)](http-server/listen-letsencrypt/main.go) + * [Socket Sharding (SO_REUSEPORT)](http-server/socket-sharding/main.go) * [Graceful Shutdown](http-server/graceful-shutdown/default-notifier/main.go) * [Notify on shutdown](http-server/notify-on-shutdown/main.go) * Custom TCP Listener * [Common net.Listener](http-server/custom-listener/main.go) - * [SO_REUSEPORT for unix systems](http-server/custom-listener/unix-reuseport/main.go) * Custom HTTP Server * [Pass a custom Server](http-server/custom-httpserver/easy-way/main.go) * [Use Iris as a single http.Handler](http-server/custom-httpserver/std-way/main.go) diff --git a/_examples/bootstrapper/main.go b/_examples/bootstrapper/main.go index 24054145..4a8e1d1e 100644 --- a/_examples/bootstrapper/main.go +++ b/_examples/bootstrapper/main.go @@ -1,9 +1,9 @@ package main import ( - "github.com/kataras/iris/v12/_examples/bootstrap/bootstrap" - "github.com/kataras/iris/v12/_examples/bootstrap/middleware/identity" - "github.com/kataras/iris/v12/_examples/bootstrap/routes" + "github.com/kataras/iris/v12/_examples/bootstrapper/bootstrap" + "github.com/kataras/iris/v12/_examples/bootstrapper/middleware/identity" + "github.com/kataras/iris/v12/_examples/bootstrapper/routes" ) func newApp() *bootstrap.Bootstrapper { diff --git a/_examples/bootstrapper/middleware/identity/identity.go b/_examples/bootstrapper/middleware/identity/identity.go index 2228fbac..6ce7f309 100644 --- a/_examples/bootstrapper/middleware/identity/identity.go +++ b/_examples/bootstrapper/middleware/identity/identity.go @@ -5,7 +5,7 @@ import ( "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/_examples/bootstrap/bootstrap" + "github.com/kataras/iris/v12/_examples/bootstrapper/bootstrap" ) // New returns a new handler which adds some headers and view data diff --git a/_examples/bootstrapper/routes/routes.go b/_examples/bootstrapper/routes/routes.go index c7b19042..3f52ea75 100644 --- a/_examples/bootstrapper/routes/routes.go +++ b/_examples/bootstrapper/routes/routes.go @@ -1,7 +1,7 @@ package routes import ( - "github.com/kataras/iris/v12/_examples/bootstrap/bootstrap" + "github.com/kataras/iris/v12/_examples/bootstrapper/bootstrap" ) // Configure registers the necessary routes to the app. diff --git a/_examples/http-server/README.md b/_examples/http-server/README.md index 0a0a43dd..d588a0c6 100644 --- a/_examples/http-server/README.md +++ b/_examples/http-server/README.md @@ -11,7 +11,8 @@ we use the `iris.Addr` which is an `iris.Runner` type ```go // Listening on tcp with network address 0.0.0.0:8080 -app.Listen(":8080") +// app.Listen(":8080") it's a shortcut of: +app.Run(iris.Addr(":8080")) ``` Sometimes you have created a standard net/http server somewhere else in your app and want to use that to serve the Iris web app @@ -66,53 +67,6 @@ func main() { } ``` -UNIX and BSD hosts can take advantage of the reuse port feature - -```go -package main - -import ( - // Package tcplisten provides customizable TCP net.Listener with various - // performance-related options: - // - // - SO_REUSEPORT. This option allows linear scaling server performance - // on multi-CPU servers. - // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. - // - // - TCP_DEFER_ACCEPT. This option expects the server reads from the accepted - // connection before writing to them. - // - // - TCP_FASTOPEN. See https://lwn.net/Articles/508865/ for details. - "github.com/valyala/tcplisten" - - "github.com/kataras/iris/v12" -) - -// go get github.com/valyala/tcplisten -// go run main.go - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello World!

") - }) - - listenerCfg := tcplisten.Config{ - ReusePort: true, - DeferAccept: true, - FastOpen: true, - } - - l, err := listenerCfg.NewListener("tcp", ":8080") - if err != nil { - app.Logger().Fatal(err) - } - - app.Run(iris.Listener(l)) -} -``` - ### HTTP/2 and Secure If you have signed file keys you can use the `iris.TLS` to serve `https` based on those certification keys diff --git a/_examples/http-server/custom-listener/unix-reuseport/main.go b/_examples/http-server/custom-listener/unix-reuseport/main.go deleted file mode 100644 index 7b67d5fc..00000000 --- a/_examples/http-server/custom-listener/unix-reuseport/main.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd rumprun - -package main - -import ( - // Package tcplisten provides customizable TCP net.Listener with various - // performance-related options: - // - // - SO_REUSEPORT. This option allows linear scaling server performance - // on multi-CPU servers. - // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. - // - // - TCP_DEFER_ACCEPT. This option expects the server reads from the accepted - // connection before writing to them. - // - // - TCP_FASTOPEN. See https://lwn.net/Articles/508865/ for details. - "github.com/valyala/tcplisten" - - "github.com/kataras/iris/v12" -) - -// You can run the same app as many times as you want. -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello World!") - }) - - listenerCfg := tcplisten.Config{ - ReusePort: true, - DeferAccept: true, - FastOpen: true, - } - - l, err := listenerCfg.NewListener("tcp4", ":8080") - if err != nil { - panic(err) - } - - app.Run(iris.Listener(l)) -} diff --git a/_examples/http-server/custom-listener/unix-reuseport/main_windows.go b/_examples/http-server/custom-listener/unix-reuseport/main_windows.go deleted file mode 100644 index 91c9720f..00000000 --- a/_examples/http-server/custom-listener/unix-reuseport/main_windows.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build windows - -package main - -func main() { - panic("windows operating system does not support this feature") -} diff --git a/_examples/http-server/listen-tls/main.go b/_examples/http-server/listen-tls/main.go index a9dee519..5dd1170e 100644 --- a/_examples/http-server/listen-tls/main.go +++ b/_examples/http-server/listen-tls/main.go @@ -18,10 +18,10 @@ func main() { // Start the server (HTTPS) on port 443, // and a secondary of (HTTP) on port :80 which redirects requests to their HTTPS version. // This is a blocking func. - app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key")) + app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key")) // Note: to disable automatic "http://" to "https://" redirections pass the `iris.TLSNoRedirect` // host configurator to TLS or AutoTLS functions, e.g: // - // app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key", iris.TLSNoRedirect)) + // app.Run(iris.TLS("127.0.0.1:443", "mycert.crt", "mykey.key", iris.TLSNoRedirect)) } diff --git a/_examples/http-server/listen-tls/mycert.cert b/_examples/http-server/listen-tls/mycert.cert deleted file mode 100644 index 39106262..00000000 --- a/_examples/http-server/listen-tls/mycert.cert +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDAzCCAeugAwIBAgIJAPDsxtKV4v3uMA0GCSqGSIb3DQEBBQUAMBgxFjAUBgNV -BAMMDTEyNy4wLjAuMTo0NDMwHhcNMTYwNjI5MTMxMjU4WhcNMjYwNjI3MTMxMjU4 -WjAYMRYwFAYDVQQDDA0xMjcuMC4wLjE6NDQzMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH -XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns -8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB -dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv -ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs -pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABo1AwTjAdBgNVHQ4EFgQU -zr1df/c9+NyTpmyiQO8g3a8NswYwHwYDVR0jBBgwFoAUzr1df/c9+NyTpmyiQO8g -3a8NswYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEACG5shtMSDgCd -MNjOF+YmD+PX3Wy9J9zehgaDJ1K1oDvBbQFl7EOJl8lRMWITSws22Wxwh8UXVibL -sscKBp14dR3e7DdbwCVIX/JyrJyOaCfy2nNBdf1B06jYFsIHvP3vtBAb9bPNOTBQ -QE0Ztu9kCqgsmu0//sHuBEeA3d3E7wvDhlqRSxTLcLtgC1NSgkFvBw0JvwgpkX6s -M5WpSBZwZv8qpplxhFfqNy8Uf+xrpSW0pGfkHumehkQGC6/Ry7raganS0aHhDPK9 -Z1bEJ2com1bFFAQsm9yIXrRVMGGCtihB2Au0Q4jpEjUbzWYM+ItZyvRAGRM6Qex6 -s/jogMeRsw== ------END CERTIFICATE----- diff --git a/_examples/http-server/listen-tls/mycert.crt b/_examples/http-server/listen-tls/mycert.crt new file mode 100644 index 00000000..9db93b09 --- /dev/null +++ b/_examples/http-server/listen-tls/mycert.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUfwMd9auWixp19UnXOmyxJ9Jkv7IwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA2MjUwOTUxNDdaFw0yMTA2 +MjUwOTUxNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDlVGyGAQ9uyfNbwZyrtYOSjLpxf5NpNToh2OzU7gy2 +OexBji5lmWBQ3oYDG+FjAkbHORPzOMNpeMwje+IjGZBw8x6E+8WoGdSzbrEZ6pUV +wKJGKEuDlx6g6HEmtv3ZwgGe20gvPjjW+oCO888dwK/mbIHrHTq4nO3o0gAdAJwu +amn9BlHU5O4RW7BQ4tLF+j/fBCACWRG1NHXA0AT8eg544GyCdyteAH11oCDsHS8/ +DAPsM6t+tZrMCIt9+9dzPdVoOmQNaMMrcz8eJohddRTK6zHe9ixZTt/soayOF7OS +QQeekbr3HPYhD450zRVplLMHx7wnph/+O+Po6bqDnUzdnkqAAwwymQapHMuHXZKN +rhdfKau3rVo1GeXLIRgeWLUoxFSm4TYshrgt+0AidLRH+dCY7MS9Ngga/sAK3vID +gSF75mFgOhY+q7nvY9Ecao6TnoNNRY29hUat4y0VwSyysUy887vHr6lMK5CrAT/l +Ch8fuu20HUCoiLwMJvA6+wpivZkuiIvWY7bVGYsEYrrW+bCNN9wCGYTZEyX++os9 +v/38wdOqGUT00ewXkjIUFCWbrnxxSr98kF3w3wPf9K4Y40MNxeR90nyX4zjXGF1/ +91msUh+iivsz9mcN9DK83fgTyOsoVLX5cm/L2UBwMacsfjBbN4djOc5IuYMar/VN +GQIDAQABo1MwUTAdBgNVHQ4EFgQUtkf+yAvqgZC8f22iJny9hFEDolMwHwYDVR0j +BBgwFoAUtkf+yAvqgZC8f22iJny9hFEDolMwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAE2QasBVru618rxupyJgEHw6r4iv7sz1Afz3Q5qJ4oSA9 +xVsrVCjr3iHRFSw8Rf670E8Ffk/JjzS65mHw6zeZj/ANBKQWLjRlqzYXeetq5HzG +SIgaG7p1RFvvzz3+leFGzjinZ6sKbfB4OB72o2YN+fO8DsDxgGKll0W4KAazizSe +HY9Pgu437tWnwF16rFO3IL47n5HzYlRoGIPOpzFoNX5+fyn9GlnKEtONF2QBKTjY +rdjvqFRByDiC74d8z/Yx8IiDRn1mTcG90JLR9+c6M7fruha9Y/rJfw+4AhVh5ZDz +Bl9rGPjwEs5zwutYvVAJzs7AVcighYP1lHKoJ7DxBDQeyBsYlUNk2l6bmZgLgGUZ ++2OyWlqc/jD2GdDsIaZ4i7QqhTI/6aYZIf5zUkblKV1aMSaDulKxRv//OwW28Jax +9EEoV7VaFb3sOkB/tZGhusXeQVtdrhahT3KkZLNwmNXoXWKJ5LjeUlFWJyV6JbDe +y/PIWWCwWqyuFCSZS+Cg3RDgAzfSxkI8uVZ+IKKJS3UluDX45lxXtbRrvTQ+oDrA +6ga5c1Vz9C4kn1K5yW4d7QIvg6vPiy7gvl+//sz9oxUM3yswInDBY0HKLgT0Uq9b +YzLDh2RSaHsgHMPy2BKqR+q2N+lpg7inAWuJM1Huq6eHFqhiyQkzsfscBd1Dpm8= +-----END CERTIFICATE----- diff --git a/_examples/http-server/listen-tls/mykey.key b/_examples/http-server/listen-tls/mykey.key index 309569b4..39f7b3af 100644 --- a/_examples/http-server/listen-tls/mykey.key +++ b/_examples/http-server/listen-tls/mykey.key @@ -1,27 +1,52 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEA0KtAOHKrcbLwWJXgRX7XSFyu4HHHpSty4bliv8ET4sLJpbZH -XeVX05Foex7PnrurDP6e+0H5TgqqcpQM17/ZlFcyKrJcHSCgV0ZDB3Sb8RLQSLns -8a+MOSbn1WZ7TkC7d/cWlKmasQRHQ2V/cWlGooyKNEPoGaEz8MbY0wn2spyIJwsB -dciERC6317VTXbiZdoD8QbAsT+tBvEHM2m2A7B7PQmHNehtyFNbSV5uZNodvv1uv -ZTnDa6IqpjFLb1b2HNFgwmaVPmmkLuy1l9PN+o6/DUnXKKBrfPAx4JOlqTKEQpWs -pnfacTE3sWkkmOSSFltAXfkXIJFKdS/hy5J/KQIDAQABAoIBAQDCd+bo9I0s8Fun -4z3Y5oYSDTZ5O/CY0O5GyXPrSzCSM4Cj7EWEj1mTdb9Ohv9tam7WNHHLrcd+4NfK -4ok5hLVs1vqM6h6IksB7taKATz+Jo0PzkzrsXvMqzERhEBo4aoGMIv2rXIkrEdas -S+pCsp8+nAWtAeBMCn0Slu65d16vQxwgfod6YZfvMKbvfhOIOShl9ejQ+JxVZcMw -Ti8sgvYmFUrdrEH3nCgptARwbx4QwlHGaw/cLGHdepfFsVaNQsEzc7m61fSO70m4 -NYJv48ZgjOooF5AccbEcQW9IxxikwNc+wpFYy5vDGzrBwS5zLZQFpoyMWFhtWdjx -hbmNn1jlAoGBAPs0ZjqsfDrH5ja4dQIdu5ErOccsmoHfMMBftMRqNG5neQXEmoLc -Uz8WeQ/QDf302aTua6E9iSjd7gglbFukVwMndQ1Q8Rwxz10jkXfiE32lFnqK0csx -ltruU6hOeSGSJhtGWBuNrT93G2lmy23fSG6BqOzdU4rn/2GPXy5zaxM/AoGBANSm -/E96RcBUiI6rDVqKhY+7M1yjLB41JrErL9a0Qfa6kYnaXMr84pOqVN11IjhNNTgl -g1lwxlpXZcZh7rYu9b7EEMdiWrJDQV7OxLDHopqUWkQ+3MHwqs6CxchyCq7kv9Df -IKqat7Me6Cyeo0MqcW+UMxlCRBxKQ9jqC7hDfZuXAoGBAJmyS8ImerP0TtS4M08i -JfsCOY21qqs/hbKOXCm42W+be56d1fOvHngBJf0YzRbO0sNo5Q14ew04DEWLsCq5 -+EsDv0hwd7VKfJd+BakV99ruQTyk5wutwaEeJK1bph12MD6L4aiqHJAyLeFldZ45 -+TUzu8mA+XaJz+U/NXtUPvU9AoGBALtl9M+tdy6I0Fa50ujJTe5eEGNAwK5WNKTI -5D2XWNIvk/Yh4shXlux+nI8UnHV1RMMX++qkAYi3oE71GsKeG55jdk3fFQInVsJQ -APGw3FDRD8M4ip62ki+u+tEr/tIlcAyHtWfjNKO7RuubWVDlZFXqCiXmSdOMdsH/ -bxiREW49AoGACWev/eOzBoQJCRN6EvU2OV0s3b6f1QsPvcaH0zc6bgbBFOGmJU8v -pXhD88tsu9exptLkGVoYZjR0n0QT/2Kkyu93jVDW/80P7VCz8DKYyAJDa4CVwZxO -MlobQSunSDKx/CCJhWkbytCyh1bngAtwSAYLXavYIlJbAzx6FvtAIw4= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +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 +W2TzuSMYNDu876twbTVQJED3mwOAQ3J7 +-----END PRIVATE KEY----- diff --git a/_examples/http-server/listen-unix/main.go b/_examples/http-server/listen-unix/main.go index 65d6e414..73096504 100644 --- a/_examples/http-server/listen-unix/main.go +++ b/_examples/http-server/listen-unix/main.go @@ -15,5 +15,3 @@ func main() { app.Run(iris.Listener(l)) } - -// Look "custom-listener/unix-reuseport" too. diff --git a/_examples/http-server/socket-sharding/main.go b/_examples/http-server/socket-sharding/main.go new file mode 100644 index 00000000..bd5d7e4a --- /dev/null +++ b/_examples/http-server/socket-sharding/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "time" + + "github.com/kataras/iris/v12" +) + +func main() { + startup := time.Now() + + app := iris.New() + app.Get("/", func(ctx iris.Context) { + s := startup.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat()) + ctx.Writef("This server started at: %s\n", s) + }) + + // This option allows linear scaling server performance on multi-CPU servers. + // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. + app.Listen(":8080", iris.WithSocketSharding) +} diff --git a/configuration.go b/configuration.go index 0c7654c9..ab5a66dd 100644 --- a/configuration.go +++ b/configuration.go @@ -192,6 +192,13 @@ func WithLogLevel(level string) Configurator { } } +// WithSocketSharding sets the `Configuration.SocketSharding` field to true. +func WithSocketSharding(app *Application) { + // Note(@kataras): It could be a host Configurator but it's an application setting in order + // to configure it through yaml/toml files as well. + app.config.SocketSharding = true +} + // WithoutServerError will cause to ignore the matched "errors" // from the main application's `Run/Listen` function. // @@ -805,10 +812,22 @@ type Configuration struct { // * "debug" LogLevel string `json:"logLevel" yaml:"LogLevel" toml:"LogLevel" env:"LOG_LEVEL"` + // SocketSharding enables SO_REUSEPORT (or SO_REUSEADDR for windows) + // on all registered Hosts. + // This option allows linear scaling server performance on multi-CPU servers. + // + // Please read the following: + // 1. https://stackoverflow.com/a/14388707 + // 2. https://stackoverflow.com/a/59692868 + // 3. https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ + // 4. (BOOK) Learning HTTP/2: A Practical Guide for Beginners: + // Page 37, To Shard or Not to Shard? + // + // Defaults to false. + SocketSharding bool `json:"socketSharding" yaml:"SocketSharding" toml:"SocketSharding" env:"SOCKET_SHARDING"` // Tunneling can be optionally set to enable ngrok http(s) tunneling for this Iris app instance. // See the `WithTunneling` Configurator too. Tunneling TunnelingConfiguration `json:"tunneling,omitempty" yaml:"Tunneling" toml:"Tunneling"` - // IgnoreServerErrors will cause to ignore the matched "errors" // from the main application's `Run` function. // This is a slice of string, not a slice of error @@ -1046,6 +1065,11 @@ func (c Configuration) GetLogLevel() string { return c.vhost } +// GetSocketSharding returns the SocketSharding field. +func (c Configuration) GetSocketSharding() bool { + return c.SocketSharding +} + // GetDisablePathCorrection returns the DisablePathCorrection field. func (c Configuration) GetDisablePathCorrection() bool { return c.DisablePathCorrection @@ -1182,6 +1206,10 @@ func WithConfiguration(c Configuration) Configurator { main.LogLevel = v } + if v := c.SocketSharding; v { + main.SocketSharding = v + } + if c.Tunneling.isEnabled() { main.Tunneling = c.Tunneling } @@ -1320,6 +1348,7 @@ func WithConfiguration(c Configuration) Configurator { func DefaultConfiguration() Configuration { return Configuration{ LogLevel: "info", + SocketSharding: false, DisableStartupLog: false, DisableInterruptHandler: false, DisablePathCorrection: false, diff --git a/context/configuration.go b/context/configuration.go index 5f09f0cb..557ac51c 100644 --- a/context/configuration.go +++ b/context/configuration.go @@ -12,6 +12,8 @@ type ConfigurationReadOnly interface { GetVHost() string // GetLogLevel returns the LogLevel field. GetLogLevel() string + // GetSocketSharding returns the SocketSharding field. + GetSocketSharding() bool // GetDisablePathCorrection returns the DisablePathCorrection field GetDisablePathCorrection() bool // GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field. diff --git a/core/host/supervisor.go b/core/host/supervisor.go index 96be33e5..915ebf85 100644 --- a/core/host/supervisor.go +++ b/core/host/supervisor.go @@ -13,9 +13,9 @@ import ( "sync/atomic" "time" - "golang.org/x/crypto/acme/autocert" - "github.com/kataras/iris/v12/core/netutil" + + "golang.org/x/crypto/acme/autocert" ) // Configurator provides an easy way to modify @@ -48,6 +48,9 @@ type Supervisor struct { // Defaults to empty. IgnoredErrors []string onErr []func(error) + + // See `iris.Configuration.SocketSharding`. + SocketSharding bool } // New returns a new host supervisor @@ -124,8 +127,8 @@ func (su *Supervisor) newListener() (net.Listener, error) { // restarts we may want for the server. // // User still be able to call .Serve instead. - // l, err := netutil.TCPKeepAlive(su.Server.Addr) - l, err := netutil.TCP(su.Server.Addr) + // l, err := netutil.TCPKeepAlive(su.Server.Addr, su.SocketReuse) + l, err := netutil.TCP(su.Server.Addr, su.SocketSharding) if err != nil { return nil, err } @@ -367,7 +370,13 @@ func (su *Supervisor) runTLS(getCertificate func(*tls.ClientHelloInfo) (*tls.Cer defer cancel() http1RedirectServer.Shutdown(ctx) }) - go http1RedirectServer.ListenAndServe() + + ln, err := netutil.TCP(":http", su.SocketSharding) + if err != nil { + return err + } + + go http1RedirectServer.Serve(ln) } if su.Server.TLSConfig == nil { @@ -401,7 +410,12 @@ func (su *Supervisor) runTLS(getCertificate func(*tls.ClientHelloInfo) (*tls.Cer } } - return su.supervise(func() error { return su.Server.ListenAndServeTLS("", "") }) + ln, err := netutil.TCP(su.Server.Addr, su.SocketSharding) + if err != nil { + return err + } + + return su.supervise(func() error { return su.Server.ServeTLS(ln, "", "") }) } // RegisterOnShutdown registers a function to call on Shutdown. diff --git a/core/netutil/tcp.go b/core/netutil/tcp.go index 169943af..8a242424 100644 --- a/core/netutil/tcp.go +++ b/core/netutil/tcp.go @@ -1,6 +1,7 @@ package netutil import ( + "context" "crypto/tls" "errors" "fmt" @@ -38,16 +39,17 @@ func (l tcpKeepAliveListener) Accept() (net.Conn, error) { } // TCP returns a new tcp(ipv6 if supported by network) and an error on failure. -func TCP(addr string) (net.Listener, error) { - l, err := net.Listen("tcp", addr) - if err != nil { - return nil, err +func TCP(addr string, reuse bool) (net.Listener, error) { + var cfg net.ListenConfig + if reuse { + cfg.Control = control } - return l, nil + + return cfg.Listen(context.Background(), "tcp", addr) } // TCPKeepAlive returns a new tcp keep alive Listener and an error on failure. -func TCPKeepAlive(addr string) (ln net.Listener, err error) { +func TCPKeepAlive(addr string, reuse bool) (ln net.Listener, err error) { // if strings.HasPrefix(addr, "127.0.0.1") { // // it's ipv4, use ipv4 tcp listener instead of the default ipv6. Don't. // ln, err = net.Listen("tcp4", addr) @@ -55,7 +57,7 @@ func TCPKeepAlive(addr string) (ln net.Listener, err error) { // ln, err = TCP(addr) // } - ln, err = TCP(addr) + ln, err = TCP(addr, reuse) if err != nil { return nil, err } @@ -110,19 +112,20 @@ func CERT(addr string, cert tls.Certificate) (net.Listener, error) { // LETSENCRYPT returns a new Automatic TLS Listener using letsencrypt.org service // receives three parameters, // the first is the host of the server, -// second can be the server name(domain) or empty if skip verification is the expected behavior (not recommended) -// and the third is optionally, the cache directory, if you skip it then the cache directory is "./certcache" +// second one should declare if the underline tcp listener can be binded more than once, +// third can be the server name(domain) or empty if skip verification is the expected behavior (not recommended), +// and the forth is optionally, the cache directory, if you skip it then the cache directory is "./certcache" // if you want to disable cache directory then simple give it a value of empty string "" // // does NOT supports localhost domains for testing. // // this is the recommended function to use when you're ready for production state. -func LETSENCRYPT(addr string, serverName string, cacheDirOptional ...string) (net.Listener, error) { +func LETSENCRYPT(addr string, reuse bool, serverName string, cacheDirOptional ...string) (net.Listener, error) { if portIdx := strings.IndexByte(addr, ':'); portIdx == -1 { addr += ":443" } - l, err := TCP(addr) + l, err := TCP(addr, reuse) if err != nil { return nil, err } diff --git a/core/netutil/tcp_soreuse_control_unix.go b/core/netutil/tcp_soreuse_control_unix.go new file mode 100644 index 00000000..3ed7f55d --- /dev/null +++ b/core/netutil/tcp_soreuse_control_unix.go @@ -0,0 +1,25 @@ +// +build !windows,!wasm + +package netutil + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +func control(network, address string, c syscall.RawConn) (err error) { + c.Control(func(fd uintptr) { + 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 + } + }) + + return +} diff --git a/core/netutil/tcp_soreuse_control_wasm.go b/core/netutil/tcp_soreuse_control_wasm.go new file mode 100644 index 00000000..a38a9d00 --- /dev/null +++ b/core/netutil/tcp_soreuse_control_wasm.go @@ -0,0 +1,9 @@ +// +build wasm + +package netutil + +import "syscall" + +func control(network, address string, c syscall.RawConn) error { + return nil +} diff --git a/core/netutil/tcp_soreuse_control_windows.go b/core/netutil/tcp_soreuse_control_windows.go new file mode 100644 index 00000000..31e7aeac --- /dev/null +++ b/core/netutil/tcp_soreuse_control_windows.go @@ -0,0 +1,13 @@ +package netutil + +import ( + "syscall" + + "golang.org/x/sys/windows" +) + +func control(network, address string, c syscall.RawConn) (err error) { + return c.Control(func(fd uintptr) { + err = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1) + }) +} diff --git a/go.mod b/go.mod index f9e087f9..09dd3c9d 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( go.etcd.io/bbolt v1.3.5 golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 golang.org/x/net v0.0.0-20200602114024-627f9648deb9 + golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd golang.org/x/text v0.3.3 golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 google.golang.org/protobuf v1.24.0 diff --git a/iris.go b/iris.go index ed473a76..0b6a6e1e 100644 --- a/iris.go +++ b/iris.go @@ -1107,6 +1107,10 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error { return err } + app.ConfigureHost(func(host *Supervisor) { + host.SocketSharding = app.config.SocketSharding + }) + app.tryStartTunneling() if len(app.Hosts) > 0 {