summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2021-01-22 11:04:09 +0300
committerGitHub <[email protected]>2021-01-22 11:04:09 +0300
commit29d6020a9e8a3713b22269ed946547c96c24d3da (patch)
treeafe4d330ecb4180e1a9970c8e250bf4f8d92c15e
parent6807441b2bf1e821e335d67567af47567c9757f3 (diff)
parent4d60db85d1c0bfeddffe1de3e28d3464949c5f6d (diff)
Merge pull request #494 from spiral/feature/allow_https_listen_on_unix_socketsv2.0.0-beta11
feat(https): Allow https to listen on unix sockets
-rw-r--r--.github/workflows/build.yml3
-rwxr-xr-x.rr.yaml4
-rwxr-xr-xMakefile2
-rw-r--r--plugins/http/config/http.go34
-rw-r--r--plugins/http/config/ssl.go69
-rw-r--r--plugins/http/config/ssl_config_test.go116
-rw-r--r--plugins/http/plugin.go61
-rw-r--r--tests/plugins/http/configs/.rr-fcgi-reqUri.yaml2
-rw-r--r--tests/plugins/http/configs/.rr-fcgi.yaml2
-rw-r--r--tests/plugins/http/configs/.rr-init.yaml2
-rw-r--r--tests/plugins/http/configs/.rr-ssl-push.yaml2
-rw-r--r--tests/plugins/http/configs/.rr-ssl-redirect.yaml2
-rw-r--r--tests/plugins/http/configs/.rr-ssl.yaml2
-rw-r--r--tests/plugins/http/http_plugin_test.go8
-rwxr-xr-xtests/plugins/rpc/config_test.go1
-rwxr-xr-xutils/network.go52
-rwxr-xr-xutils/network_windows.go54
17 files changed, 318 insertions, 98 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7f490208..ed9d7f5a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -73,6 +73,7 @@ jobs:
go test -v -race -tags=debug ./pkg/worker
go test -v -race -tags=debug ./pkg/worker_watcher
go test -v -race -tags=debug ./tests/plugins/http
+ go test -v -race -tags=debug ./plugins/http/config
go test -v -race -tags=debug ./tests/plugins/informer
go test -v -race -tags=debug ./tests/plugins/reload
go test -v -race -tags=debug ./tests/plugins/server
@@ -103,6 +104,7 @@ jobs:
go test -v -race -tags=debug ./pkg/socket
go test -v -race -tags=debug ./pkg/worker
go test -v -race -tags=debug ./pkg/worker_watcher
+ go test -v -race -tags=debug ./plugins/http/config
go test -v -race -tags=debug ./tests/plugins/http
go test -v -race -tags=debug ./tests/plugins/informer
go test -v -race -tags=debug ./tests/plugins/reload
@@ -133,6 +135,7 @@ jobs:
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/socket.txt -covermode=atomic ./pkg/socket
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/worker.txt -covermode=atomic ./pkg/worker
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/worker_stack.txt -covermode=atomic ./pkg/worker_watcher
+ go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/http_config.txt -covermode=atomic ./plugins/http/config
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/http.txt -covermode=atomic ./tests/plugins/http
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/informer.txt -covermode=atomic ./tests/plugins/informer
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/reload.txt -covermode=atomic ./tests/plugins/reload
diff --git a/.rr.yaml b/.rr.yaml
index ca638aa9..a4726066 100755
--- a/.rr.yaml
+++ b/.rr.yaml
@@ -16,6 +16,7 @@ logs:
level: debug
http:
+ # host and port separated by semicolon
address: 127.0.0.1:44933
max_request_size: 1024
middleware: [ "gzip", "headers" ]
@@ -70,7 +71,8 @@ http:
max_worker_memory: 100
# ssl:
- # port: 8892
+ # host and port separated by semicolon (default :443)
+ # address: :8892
# redirect: false
# cert: fixtures/server.crt
# key: fixtures/server.key
diff --git a/Makefile b/Makefile
index d003ce53..2c573f9e 100755
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,7 @@ test_coverage:
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/static.out -covermode=atomic ./tests/plugins/static
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/boltdb_unit.out -covermode=atomic ./plugins/kv/boltdb
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/kv_unit.out -covermode=atomic ./plugins/kv/memory
+ go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/http_config.out -covermode=atomic ./plugins/http/config
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/memcached_unit.out -covermode=atomic ./plugins/kv/memcached
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/boltdb.out -covermode=atomic ./tests/plugins/kv/boltdb
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage/memory.out -covermode=atomic ./tests/plugins/kv/memory
@@ -65,6 +66,7 @@ test: ## Run application tests
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./pkg/worker
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./pkg/worker_watcher
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./tests/plugins/http
+ go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./plugins/http/config
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./tests/plugins/informer
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./tests/plugins/reload
go test -v -race -cover -tags=debug -coverpkg=./... -covermode=atomic ./tests/plugins/server
diff --git a/plugins/http/config/http.go b/plugins/http/config/http.go
index 76547fde..bd689918 100644
--- a/plugins/http/config/http.go
+++ b/plugins/http/config/http.go
@@ -2,7 +2,6 @@ package config
import (
"net"
- "os"
"runtime"
"strings"
"time"
@@ -13,7 +12,7 @@ import (
// HTTP configures RoadRunner HTTP server.
type HTTP struct {
- // Port and port to handle as http server.
+ // Host and port to handle as http server.
Address string
// SSLConfig defines https server options.
@@ -97,8 +96,8 @@ func (c *HTTP) InitDefaults() error {
c.SSLConfig = &SSL{}
}
- if c.SSLConfig.Port == 0 {
- c.SSLConfig.Port = 443
+ if c.SSLConfig.Address == "" {
+ c.SSLConfig.Address = ":443"
}
err := c.HTTP2Config.InitDefaults()
@@ -191,30 +190,9 @@ func (c *HTTP) Valid() error {
}
if c.EnableTLS() {
- if _, err := os.Stat(c.SSLConfig.Key); err != nil {
- if os.IsNotExist(err) {
- return errors.E(op, errors.Errorf("key file '%s' does not exists", c.SSLConfig.Key))
- }
-
- return err
- }
-
- if _, err := os.Stat(c.SSLConfig.Cert); err != nil {
- if os.IsNotExist(err) {
- return errors.E(op, errors.Errorf("cert file '%s' does not exists", c.SSLConfig.Cert))
- }
-
- return err
- }
-
- // RootCA is optional, but if provided - check it
- if c.SSLConfig.RootCA != "" {
- if _, err := os.Stat(c.SSLConfig.RootCA); err != nil {
- if os.IsNotExist(err) {
- return errors.E(op, errors.Errorf("root ca path provided, but path '%s' does not exists", c.SSLConfig.RootCA))
- }
- return err
- }
+ err := c.SSLConfig.Valid()
+ if err != nil {
+ return errors.E(op, err)
}
}
diff --git a/plugins/http/config/ssl.go b/plugins/http/config/ssl.go
index aae6e920..c33dbce4 100644
--- a/plugins/http/config/ssl.go
+++ b/plugins/http/config/ssl.go
@@ -1,9 +1,17 @@
package config
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/spiral/errors"
+)
+
// SSL defines https server configuration.
type SSL struct {
- // Port to listen as HTTPS server, defaults to 443.
- Port int
+ // Address to listen as HTTPS server, defaults to 0.0.0.0:443.
+ Address string
// Redirect when enabled forces all http connections to switch to https.
Redirect bool
@@ -16,4 +24,61 @@ type SSL struct {
// Root CA file
RootCA string
+
+ // internal
+ host string
+ Port int
+}
+
+func (s *SSL) Valid() error {
+ const op = errors.Op("ssl_valid")
+
+ parts := strings.Split(s.Address, ":")
+ switch len(parts) {
+ // :443 form
+ // localhost:443 form
+ // use 0.0.0.0 as host and 443 as port
+ case 2:
+ if parts[0] == "" {
+ s.host = "0.0.0.0"
+ } else {
+ s.host = parts[0]
+ }
+
+ port, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return errors.E(op, err)
+ }
+ s.Port = port
+ default:
+ return errors.E(op, errors.Errorf("unknown format, accepted format is [:<port> or <host>:<port>], provided: %s", s.Address))
+ }
+
+ if _, err := os.Stat(s.Key); err != nil {
+ if os.IsNotExist(err) {
+ return errors.E(op, errors.Errorf("key file '%s' does not exists", s.Key))
+ }
+
+ return err
+ }
+
+ if _, err := os.Stat(s.Cert); err != nil {
+ if os.IsNotExist(err) {
+ return errors.E(op, errors.Errorf("cert file '%s' does not exists", s.Cert))
+ }
+
+ return err
+ }
+
+ // RootCA is optional, but if provided - check it
+ if s.RootCA != "" {
+ if _, err := os.Stat(s.RootCA); err != nil {
+ if os.IsNotExist(err) {
+ return errors.E(op, errors.Errorf("root ca path provided, but path '%s' does not exists", s.RootCA))
+ }
+ return err
+ }
+ }
+
+ return nil
}
diff --git a/plugins/http/config/ssl_config_test.go b/plugins/http/config/ssl_config_test.go
new file mode 100644
index 00000000..1f5fef0a
--- /dev/null
+++ b/plugins/http/config/ssl_config_test.go
@@ -0,0 +1,116 @@
+package config
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSSL_Valid1(t *testing.T) {
+ conf := &SSL{
+ Address: "",
+ Redirect: false,
+ Key: "",
+ Cert: "",
+ RootCA: "",
+ host: "",
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
+
+func TestSSL_Valid2(t *testing.T) {
+ conf := &SSL{
+ Address: ":hello",
+ Redirect: false,
+ Key: "",
+ Cert: "",
+ RootCA: "",
+ host: "",
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
+
+func TestSSL_Valid3(t *testing.T) {
+ conf := &SSL{
+ Address: ":555",
+ Redirect: false,
+ Key: "",
+ Cert: "",
+ RootCA: "",
+ host: "",
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
+
+func TestSSL_Valid4(t *testing.T) {
+ conf := &SSL{
+ Address: ":555",
+ Redirect: false,
+ Key: "../../../tests/plugins/http/fixtures/server.key",
+ Cert: "../../../tests/plugins/http/fixtures/server.crt",
+ RootCA: "",
+ host: "",
+ // private
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.NoError(t, err)
+}
+
+func TestSSL_Valid5(t *testing.T) {
+ conf := &SSL{
+ Address: "a:b:c",
+ Redirect: false,
+ Key: "../../../tests/plugins/http/fixtures/server.key",
+ Cert: "../../../tests/plugins/http/fixtures/server.crt",
+ RootCA: "",
+ host: "",
+ // private
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
+
+func TestSSL_Valid6(t *testing.T) {
+ conf := &SSL{
+ Address: ":",
+ Redirect: false,
+ Key: "../../../tests/plugins/http/fixtures/server.key",
+ Cert: "../../../tests/plugins/http/fixtures/server.crt",
+ RootCA: "",
+ host: "",
+ // private
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
+
+func TestSSL_Valid7(t *testing.T) {
+ conf := &SSL{
+ Address: "localhost:555:1",
+ Redirect: false,
+ Key: "../../../tests/plugins/http/fixtures/server.key",
+ Cert: "../../../tests/plugins/http/fixtures/server.crt",
+ RootCA: "",
+ host: "",
+ // private
+ Port: 0,
+ }
+
+ err := conf.Valid()
+ assert.Error(t, err)
+}
diff --git a/plugins/http/plugin.go b/plugins/http/plugin.go
index 35acd2b7..249d2e57 100644
--- a/plugins/http/plugin.go
+++ b/plugins/http/plugin.go
@@ -36,6 +36,9 @@ const (
// RR_HTTP env variable key (internal) if the HTTP presents
RR_HTTP = "RR_HTTP" //nolint:golint,stylecheck
+
+ // HTTPS_SCHEME
+ HTTPS_SCHEME = "https" //nolint:golint,stylecheck
)
// Middleware interface
@@ -154,9 +157,9 @@ func (s *Plugin) Serve() chan error {
if s.cfg.EnableHTTP() {
if s.cfg.EnableH2C() {
- s.http = &http.Server{Addr: s.cfg.Address, Handler: h2c.NewHandler(s, &http2.Server{})}
+ s.http = &http.Server{Handler: h2c.NewHandler(s, &http2.Server{})}
} else {
- s.http = &http.Server{Addr: s.cfg.Address, Handler: s}
+ s.http = &http.Server{Handler: s}
}
}
@@ -190,9 +193,15 @@ func (s *Plugin) Serve() chan error {
if s.http != nil {
go func() {
- httpErr := s.http.ListenAndServe()
- if httpErr != nil && httpErr != http.ErrServerClosed {
- errCh <- errors.E(op, httpErr)
+ l, err := utils.CreateListener(s.cfg.Address)
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return
+ }
+
+ err = s.http.Serve(l)
+ if err != nil && err != http.ErrServerClosed {
+ errCh <- errors.E(op, err)
return
}
}()
@@ -200,13 +209,20 @@ func (s *Plugin) Serve() chan error {
if s.https != nil {
go func() {
- httpErr := s.https.ListenAndServeTLS(
+ l, err := utils.CreateListener(s.cfg.SSLConfig.Address)
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return
+ }
+
+ err = s.https.ServeTLS(
+ l,
s.cfg.SSLConfig.Cert,
s.cfg.SSLConfig.Key,
)
- if httpErr != nil && httpErr != http.ErrServerClosed {
- errCh <- errors.E(op, httpErr)
+ if err != nil && err != http.ErrServerClosed {
+ errCh <- errors.E(op, err)
return
}
}()
@@ -270,7 +286,8 @@ func (s *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- if s.redirect(w, r) {
+ if s.https != nil && r.TLS == nil && s.cfg.SSLConfig.Redirect {
+ s.redirect(w, r)
return
}
@@ -362,21 +379,19 @@ func (s *Plugin) Status() checker.Status {
}
}
-func (s *Plugin) redirect(w http.ResponseWriter, r *http.Request) bool {
- if s.https != nil && r.TLS == nil && s.cfg.SSLConfig.Redirect {
- target := &url.URL{
- Scheme: "https",
- Host: s.tlsAddr(r.Host, false),
- Path: r.URL.Path,
- RawQuery: r.URL.RawQuery,
- }
-
- http.Redirect(w, r, target.String(), http.StatusTemporaryRedirect)
- return true
+func (s *Plugin) redirect(w http.ResponseWriter, r *http.Request) {
+ target := &url.URL{
+ Scheme: HTTPS_SCHEME,
+ // host or host:port
+ Host: s.tlsAddr(r.Host, false),
+ Path: r.URL.Path,
+ RawQuery: r.URL.RawQuery,
}
- return false
+
+ http.Redirect(w, r, target.String(), http.StatusTemporaryRedirect)
}
+//go:inline
func headerContainsUpgrade(r *http.Request, s *Plugin) bool {
if _, ok := r.Header["Upgrade"]; ok {
// https://golang.org/pkg/net/http/#Hijacker
@@ -468,7 +483,7 @@ func (s *Plugin) initSSL() *http.Server {
DefaultCipherSuites = append(DefaultCipherSuites, topCipherSuites...)
DefaultCipherSuites = append(DefaultCipherSuites, defaultCipherSuitesTLS13...)
- server := &http.Server{
+ sslServer := &http.Server{
Addr: s.tlsAddr(s.cfg.Address, true),
Handler: s,
TLSConfig: &tls.Config{
@@ -484,7 +499,7 @@ func (s *Plugin) initSSL() *http.Server {
},
}
- return server
+ return sslServer
}
// init http/2 server
diff --git a/tests/plugins/http/configs/.rr-fcgi-reqUri.yaml b/tests/plugins/http/configs/.rr-fcgi-reqUri.yaml
index 99002777..05c3d40a 100644
--- a/tests/plugins/http/configs/.rr-fcgi-reqUri.yaml
+++ b/tests/plugins/http/configs/.rr-fcgi-reqUri.yaml
@@ -22,7 +22,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8890
+ address: :8890
redirect: false
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/configs/.rr-fcgi.yaml b/tests/plugins/http/configs/.rr-fcgi.yaml
index 110b68f4..cfd4b79b 100644
--- a/tests/plugins/http/configs/.rr-fcgi.yaml
+++ b/tests/plugins/http/configs/.rr-fcgi.yaml
@@ -22,7 +22,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8889
+ address: :8889
redirect: false
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/configs/.rr-init.yaml b/tests/plugins/http/configs/.rr-init.yaml
index b541e6de..01b90b44 100644
--- a/tests/plugins/http/configs/.rr-init.yaml
+++ b/tests/plugins/http/configs/.rr-init.yaml
@@ -26,7 +26,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8892
+ address: :8892
redirect: false
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/configs/.rr-ssl-push.yaml b/tests/plugins/http/configs/.rr-ssl-push.yaml
index ae9fbc02..11a8ddd3 100644
--- a/tests/plugins/http/configs/.rr-ssl-push.yaml
+++ b/tests/plugins/http/configs/.rr-ssl-push.yaml
@@ -22,7 +22,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8894
+ address: :8894
redirect: true
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/configs/.rr-ssl-redirect.yaml b/tests/plugins/http/configs/.rr-ssl-redirect.yaml
index d052e649..e49a73ed 100644
--- a/tests/plugins/http/configs/.rr-ssl-redirect.yaml
+++ b/tests/plugins/http/configs/.rr-ssl-redirect.yaml
@@ -22,7 +22,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8895
+ address: :8895
redirect: true
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/configs/.rr-ssl.yaml b/tests/plugins/http/configs/.rr-ssl.yaml
index c3e45365..8a0f16b8 100644
--- a/tests/plugins/http/configs/.rr-ssl.yaml
+++ b/tests/plugins/http/configs/.rr-ssl.yaml
@@ -21,7 +21,7 @@ http:
destroy_timeout: 60s
ssl:
- port: 8893
+ address: :8893
redirect: false
cert: fixtures/server.crt
key: fixtures/server.key
diff --git a/tests/plugins/http/http_plugin_test.go b/tests/plugins/http/http_plugin_test.go
index 23628c72..72ae05a0 100644
--- a/tests/plugins/http/http_plugin_test.go
+++ b/tests/plugins/http/http_plugin_test.go
@@ -46,7 +46,7 @@ func TestHTTPInit(t *testing.T) {
cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel))
assert.NoError(t, err)
- rIn := makeConfig("6001", "15395", "7921", "8892", "false", "false", "php ../../http/client.php echo pipes")
+ rIn := makeConfig("6001", "15395", "7921", ":8892", "false", "false", "php ../../http/client.php echo pipes")
cfg := &config.Viper{
ReadInCfg: rIn,
Type: "yaml",
@@ -1264,7 +1264,7 @@ func getHeader(url string, h map[string]string) (string, *http.Response, error)
return string(b), r, err
}
-func makeConfig(rpcPort, httpPort, fcgiPort, sslPort, redirect, http2Enabled, command string) []byte {
+func makeConfig(rpcPort, httpPort, fcgiPort, sslAddress, redirect, http2Enabled, command string) []byte {
return []byte(fmt.Sprintf(`
rpc:
listen: tcp://127.0.0.1:%s
@@ -1293,7 +1293,7 @@ http:
destroyTimeout: 60s
ssl:
- port: %s
+ address: %s
redirect: %s
cert: fixtures/server.crt
key: fixtures/server.key
@@ -1307,5 +1307,5 @@ http:
logs:
mode: development
level: error
-`, rpcPort, command, httpPort, sslPort, redirect, fcgiPort, http2Enabled))
+`, rpcPort, command, httpPort, sslAddress, redirect, fcgiPort, http2Enabled))
}
diff --git a/tests/plugins/rpc/config_test.go b/tests/plugins/rpc/config_test.go
index df5fa391..34ca9cee 100755
--- a/tests/plugins/rpc/config_test.go
+++ b/tests/plugins/rpc/config_test.go
@@ -51,7 +51,6 @@ func Test_Config_Error(t *testing.T) {
ln, err := cfg.Listener()
assert.Nil(t, ln)
assert.Error(t, err)
- assert.Equal(t, "invalid DSN (tcp://:6001, unix://file.sock)", err.Error())
}
func Test_Config_ErrorMethod(t *testing.T) {
diff --git a/utils/network.go b/utils/network.go
index fcfc4ace..c9db0e68 100755
--- a/utils/network.go
+++ b/utils/network.go
@@ -3,7 +3,6 @@
package utils
import (
- "errors"
"fmt"
"net"
"os"
@@ -16,36 +15,49 @@ import (
// CreateListener crates socket listener based on DSN definition.
func CreateListener(address string) (net.Listener, error) {
dsn := strings.Split(address, "://")
- if len(dsn) != 2 {
- return nil, errors.New("invalid DSN (tcp://:6001, unix://file.sock)")
- }
-
- if dsn[0] != "unix" && dsn[0] != "tcp" {
- return nil, errors.New("invalid Protocol (tcp://:6001, unix://file.sock)")
- }
- // create unix listener
- if dsn[0] == "unix" {
- // check if the file exist
- if fileExists(dsn[1]) {
- err := syscall.Unlink(dsn[1])
- if err != nil {
- return nil, fmt.Errorf("error during the unlink syscall: error %v", err)
+ switch len(dsn) {
+ case 1:
+ // assume, that there is no prefix here [127.0.0.1:8000]
+ return createTCPListener(dsn[0])
+ case 2:
+ // we got two part here, first part is the transport, second - address
+ // [tcp://127.0.0.1:8000] OR [unix:///path/to/unix.socket] OR [error://path]
+ // where error is wrong transport name
+ switch dsn[0] {
+ case "unix":
+ // check of file exist. If exist, unlink
+ if fileExists(dsn[1]) {
+ err := syscall.Unlink(dsn[1])
+ if err != nil {
+ return nil, fmt.Errorf("error during the unlink syscall: error %v", err)
+ }
}
+ return net.Listen(dsn[0], dsn[1])
+ case "tcp":
+ return createTCPListener(dsn[1])
+ // not an tcp or unix
+ default:
+ return nil, fmt.Errorf("invalid Protocol ([tcp://]:6001, unix://file.sock), address: %s", address)
}
- return net.Listen(dsn[0], dsn[1])
+ // wrong number of split parts
+ default:
+ return nil, fmt.Errorf("wrong number of parsed protocol parts, address: %s", address)
}
+}
- // configure and create tcp4 listener
+func createTCPListener(addr string) (net.Listener, error) {
cfg := tcplisten.Config{
ReusePort: true,
DeferAccept: true,
FastOpen: true,
Backlog: 0,
}
-
- // only tcp4 is currently supported
- return cfg.NewListener("tcp4", dsn[1])
+ listener, err := cfg.NewListener("tcp4", addr)
+ if err != nil {
+ return nil, err
+ }
+ return listener, nil
}
// fileExists checks if a file exists and is not a directory before we
diff --git a/utils/network_windows.go b/utils/network_windows.go
index ebe343a3..a07ac351 100755
--- a/utils/network_windows.go
+++ b/utils/network_windows.go
@@ -3,33 +3,61 @@
package utils
import (
- "errors"
"fmt"
"net"
"os"
"strings"
"syscall"
+
+ "github.com/valyala/tcplisten"
)
// CreateListener crates socket listener based on DSN definition.
func CreateListener(address string) (net.Listener, error) {
dsn := strings.Split(address, "://")
- if len(dsn) != 2 {
- return nil, errors.New("invalid DSN (tcp://:6001, unix://file.sock)")
- }
-
- if dsn[0] != "unix" && dsn[0] != "tcp" {
- return nil, errors.New("invalid Protocol (tcp://:6001, unix://file.sock)")
- }
- if dsn[0] == "unix" && fileExists(dsn[1]) {
- err := syscall.Unlink(dsn[1])
- if err != nil {
- return nil, fmt.Errorf("error during the unlink syscall: error %v", err)
+ switch len(dsn) {
+ case 1:
+ // assume, that there is no prefix here [127.0.0.1:8000]
+ return createTCPListener(dsn[0])
+ case 2:
+ // we got two part here, first part is the transport, second - address
+ // [tcp://127.0.0.1:8000] OR [unix:///path/to/unix.socket] OR [error://path]
+ // where error is wrong transport name
+ switch dsn[0] {
+ case "unix":
+ // check of file exist. If exist, unlink
+ if fileExists(dsn[1]) {
+ err := syscall.Unlink(dsn[1])
+ if err != nil {
+ return nil, fmt.Errorf("error during the unlink syscall: error %v", err)
+ }
+ }
+ return net.Listen(dsn[0], dsn[1])
+ case "tcp":
+ return createTCPListener(dsn[1])
+ // not an tcp or unix
+ default:
+ return nil, fmt.Errorf("invalid Protocol ([tcp://]:6001, unix://file.sock), address: %s", address)
}
+ // wrong number of split parts
+ default:
+ return nil, fmt.Errorf("wrong number of parsed protocol parts, address: %s", address)
}
+}
- return net.Listen(dsn[0], dsn[1])
+func createTCPListener(addr string) (net.Listener, error) {
+ cfg := tcplisten.Config{
+ ReusePort: true,
+ DeferAccept: true,
+ FastOpen: true,
+ Backlog: 0,
+ }
+ listener, err := cfg.NewListener("tcp4", addr)
+ if err != nil {
+ return nil, err
+ }
+ return listener, nil
}
// fileExists checks if a file exists and is not a directory before we