diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 2788ddc33b..f320540311 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -590,7 +590,7 @@ func accountImport(c *cli.Context) error { Address %v Keystore file: %v -The key is now encrypted; losing the password will result in permanently losing +The key is now encrypted; losing the password will result in permanently losing access to the key and all associated funds! Make sure to backup keystore and passwords in a safe location.`, @@ -743,7 +743,7 @@ func signer(c *cli.Context) error { // start http server httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.HTTPListenAddrFlag.Name), port) - httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) + httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, c.String(utils.HTTPListenProtocolFlag.Name), rpc.DefaultHTTPTimeouts, handler) if err != nil { utils.Fatalf("Could not start RPC api: %v", err) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5ba0702498..f418167e72 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -155,6 +155,7 @@ var ( rpcFlags = []cli.Flag{ utils.HTTPEnabledFlag, utils.HTTPListenAddrFlag, + utils.HTTPListenProtocolFlag, utils.HTTPPortFlag, utils.HTTPCORSDomainFlag, utils.AuthListenFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 08de71ee83..cd71528c57 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -28,6 +28,7 @@ import ( "math/big" "net/http" "os" + "path" "path/filepath" godebug "runtime/debug" "strconv" @@ -689,6 +690,12 @@ var ( Value: node.DefaultHTTPHost, Category: flags.APICategory, } + HTTPListenProtocolFlag = &cli.StringFlag{ + Name: "http.proto", + Usage: "HTTP-RPC server listening protocol (tcp,unix)", + Value: node.DefaultHTTPProtocol, + Category: flags.APICategory, + } HTTPPortFlag = &cli.IntFlag{ Name: "http.port", Usage: "HTTP-RPC server listening port", @@ -1169,12 +1176,23 @@ func SplitAndTrim(input string) (ret []string) { // command line flags, returning empty if the HTTP endpoint is disabled. func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.Bool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" { - cfg.HTTPHost = "127.0.0.1" - if ctx.IsSet(HTTPListenAddrFlag.Name) { - cfg.HTTPHost = ctx.String(HTTPListenAddrFlag.Name) + + if HTTPListenProtocolFlag.Name == "unix" { + cfg.HTTPHost = path.Join(os.TempDir(), "geth.http.sock") + } else { + cfg.HTTPHost = "127.0.0.1" + if ctx.IsSet(HTTPListenAddrFlag.Name) { + cfg.HTTPHost = ctx.String(HTTPListenAddrFlag.Name) + } } } + if ctx.IsSet(HTTPListenProtocolFlag.Name) { + cfg.HTTPProto = ctx.String(HTTPListenProtocolFlag.Name) + } else { + cfg.HTTPProto = "tcp" + } + if ctx.IsSet(HTTPPortFlag.Name) { cfg.HTTPPort = ctx.Int(HTTPPortFlag.Name) } diff --git a/node/api.go b/node/api.go index 15892a270b..eca4dac672 100644 --- a/node/api.go +++ b/node/api.go @@ -155,7 +155,7 @@ func (api *adminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) } // StartHTTP starts the HTTP RPC API server. -func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { +func (api *adminAPI) StartHTTP(proto *string, host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -196,7 +196,7 @@ func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *stri } } - if err := api.node.http.setListenAddr(*host, *port); err != nil { + if err := api.node.http.setListenAddr(*proto, *host, *port); err != nil { return false, err } if err := api.node.http.enableRPC(api.node.rpcAPIs, config); err != nil { @@ -210,9 +210,9 @@ func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *stri // StartRPC starts the HTTP RPC API server. // Deprecated: use StartHTTP instead. -func (api *adminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { +func (api *adminAPI) StartRPC(proto *string, host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { log.Warn("Deprecation warning", "method", "admin.StartRPC", "use-instead", "admin.StartHTTP") - return api.StartHTTP(host, port, cors, apis, vhosts) + return api.StartHTTP(proto, host, port, cors, apis, vhosts) } // StopHTTP shuts down the HTTP server. @@ -229,7 +229,7 @@ func (api *adminAPI) StopRPC() (bool, error) { } // StartWS starts the websocket RPC API server. -func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { +func (api *adminAPI) StartWS(proto *string, host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -266,7 +266,7 @@ func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, ap // Enable WebSocket on the server. server := api.node.wsServerForPort(*port, false) - if err := server.setListenAddr(*host, *port); err != nil { + if err := server.setListenAddr(*proto, *host, *port); err != nil { return false, err } openApis, _ := api.node.getAPIs() diff --git a/node/api_test.go b/node/api_test.go index 8761c4883e..85fc44dc0e 100644 --- a/node/api_test.go +++ b/node/api_test.go @@ -69,7 +69,7 @@ func TestStartRPC(t *testing.T) { name: "rpc enabled through API", cfg: Config{}, fn: func(t *testing.T, n *Node, api *adminAPI) { - _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) + _, err := api.StartHTTP(sp("tcp"), sp("127.0.0.1"), ip(0), nil, nil, nil) assert.NoError(t, err) }, wantReachable: true, @@ -90,14 +90,14 @@ func TestStartRPC(t *testing.T) { port := listener.Addr().(*net.TCPAddr).Port // Now try to start RPC on that port. This should fail. - _, err = api.StartHTTP(sp("127.0.0.1"), ip(port), nil, nil, nil) + _, err = api.StartHTTP(sp("tcp"), sp("127.0.0.1"), ip(port), nil, nil, nil) if err == nil { t.Fatal("StartHTTP should have failed on port", port) } // Try again after unblocking the port. It should work this time. listener.Close() - _, err = api.StartHTTP(sp("127.0.0.1"), ip(port), nil, nil, nil) + _, err = api.StartHTTP(sp("tcp"), sp("127.0.0.1"), ip(port), nil, nil, nil) assert.NoError(t, err) }, wantReachable: true, @@ -144,7 +144,7 @@ func TestStartRPC(t *testing.T) { name: "ws enabled through API", cfg: Config{}, fn: func(t *testing.T, n *Node, api *adminAPI) { - _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) + _, err := api.StartWS(sp("tcp"), sp("127.0.0.1"), ip(0), nil, nil) assert.NoError(t, err) }, wantReachable: true, @@ -184,7 +184,7 @@ func TestStartRPC(t *testing.T) { cfg: Config{HTTPHost: "127.0.0.1"}, fn: func(t *testing.T, n *Node, api *adminAPI) { wsport := n.http.port - _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) + _, err := api.StartWS(sp("tcp"), sp("127.0.0.1"), ip(wsport), nil, nil) assert.NoError(t, err) }, wantReachable: true, @@ -197,7 +197,7 @@ func TestStartRPC(t *testing.T) { cfg: Config{HTTPHost: "127.0.0.1"}, fn: func(t *testing.T, n *Node, api *adminAPI) { wsport := n.http.port - _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) + _, err := api.StartWS(sp("tcp"), sp("127.0.0.1"), ip(wsport), nil, nil) assert.NoError(t, err) _, err = api.StopWS() @@ -211,11 +211,11 @@ func TestStartRPC(t *testing.T) { { name: "rpc stopped with ws enabled", fn: func(t *testing.T, n *Node, api *adminAPI) { - _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) + _, err := api.StartHTTP(sp("tcp"), sp("127.0.0.1"), ip(0), nil, nil, nil) assert.NoError(t, err) wsport := n.http.port - _, err = api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) + _, err = api.StartWS(sp("tcp"), sp("127.0.0.1"), ip(wsport), nil, nil) assert.NoError(t, err) _, err = api.StopHTTP() @@ -229,11 +229,11 @@ func TestStartRPC(t *testing.T) { { name: "rpc enabled after ws", fn: func(t *testing.T, n *Node, api *adminAPI) { - _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) + _, err := api.StartWS(sp("tcp"), sp("127.0.0.1"), ip(0), nil, nil) assert.NoError(t, err) wsport := n.http.port - _, err = api.StartHTTP(sp("127.0.0.1"), ip(wsport), nil, nil, nil) + _, err = api.StartHTTP(sp("tcp"), sp("127.0.0.1"), ip(wsport), nil, nil, nil) assert.NoError(t, err) }, wantReachable: true, diff --git a/node/config.go b/node/config.go index 37a7d5837f..9a141c6a6f 100644 --- a/node/config.go +++ b/node/config.go @@ -105,6 +105,10 @@ type Config struct { // field is empty, no HTTP API endpoint will be started. HTTPHost string + // HTTPProto is the protocol on which the HTTP RPC server will bind. + // Supported values are tcp, unix. HTTPPort is ignored if HTTPProto == unix + HTTPProto string + // HTTPPort is the TCP port number on which to start the HTTP RPC server. The // default zero value is/ valid and will pick a port number randomly (useful // for ephemeral nodes). diff --git a/node/defaults.go b/node/defaults.go index 96ebed81c5..df6c911374 100644 --- a/node/defaults.go +++ b/node/defaults.go @@ -28,14 +28,15 @@ import ( ) const ( - DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server - DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server - DefaultWSHost = "localhost" // Default host interface for the websocket RPC server - DefaultWSPort = 8546 // Default TCP port for the websocket RPC server - DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server - DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server - DefaultAuthHost = "localhost" // Default host interface for the authenticated apis - DefaultAuthPort = 8551 // Default port for the authenticated apis + DefaultHTTPProtocol = "tcp" // Default protocol for the HTTP RPC SERVER + DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server + DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server + DefaultWSHost = "localhost" // Default host interface for the websocket RPC server + DefaultWSPort = 8546 // Default TCP port for the websocket RPC server + DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server + DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server + DefaultAuthHost = "localhost" // Default host interface for the authenticated apis + DefaultAuthPort = 8551 // Default port for the authenticated apis ) var ( diff --git a/node/endpoints.go b/node/endpoints.go index 14c12fd1f1..ea1b001b48 100644 --- a/node/endpoints.go +++ b/node/endpoints.go @@ -26,13 +26,13 @@ import ( ) // StartHTTPEndpoint starts the HTTP RPC endpoint. -func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (*http.Server, net.Addr, error) { +func StartHTTPEndpoint(endpoint string, protocol string, timeouts rpc.HTTPTimeouts, handler http.Handler) (*http.Server, net.Addr, error) { // start the HTTP listener var ( listener net.Listener err error ) - if listener, err = net.Listen("tcp", endpoint); err != nil { + if listener, err = net.Listen(protocol, endpoint); err != nil { return nil, nil, err } // make sure timeout values are meaningful diff --git a/node/node.go b/node/node.go index 112a771ab0..12da410534 100644 --- a/node/node.go +++ b/node/node.go @@ -404,7 +404,7 @@ func (n *Node) startRPC() error { ) initHttp := func(server *httpServer, port int) error { - if err := server.setListenAddr(n.config.HTTPHost, port); err != nil { + if err := server.setListenAddr(n.config.HTTPProto, n.config.HTTPHost, port); err != nil { return err } if err := server.enableRPC(openAPIs, httpConfig{ @@ -421,7 +421,7 @@ func (n *Node) startRPC() error { initWS := func(port int) error { server := n.wsServerForPort(port, false) - if err := server.setListenAddr(n.config.WSHost, port); err != nil { + if err := server.setListenAddr(n.config.HTTPProto, n.config.WSHost, port); err != nil { return err } if err := server.enableWS(openAPIs, wsConfig{ @@ -438,7 +438,7 @@ func (n *Node) startRPC() error { initAuth := func(port int, secret []byte) error { // Enable auth via HTTP server := n.httpAuth - if err := server.setListenAddr(n.config.AuthAddr, port); err != nil { + if err := server.setListenAddr(n.config.HTTPProto, n.config.AuthAddr, port); err != nil { return err } if err := server.enableRPC(allAPIs, httpConfig{ @@ -453,7 +453,7 @@ func (n *Node) startRPC() error { servers = append(servers, server) // Enable auth via WS server = n.wsServerForPort(port, true) - if err := server.setListenAddr(n.config.AuthAddr, port); err != nil { + if err := server.setListenAddr(n.config.HTTPProto, n.config.AuthAddr, port); err != nil { return err } if err := server.enableWS(allAPIs, wsConfig{ diff --git a/node/rpcstack.go b/node/rpcstack.go index 97d591642c..3783fac01e 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -77,6 +77,7 @@ type httpServer struct { // These are set by setListenAddr. endpoint string + proto string host string port int @@ -97,15 +98,15 @@ func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer { // setListenAddr configures the listening address of the server. // The address can only be set while the server isn't running. -func (h *httpServer) setListenAddr(host string, port int) error { +func (h *httpServer) setListenAddr(proto string, host string, port int) error { h.mu.Lock() defer h.mu.Unlock() - if h.listener != nil && (host != h.host || port != h.port) { + if h.listener != nil && (host != h.host || port != h.port || proto != h.proto) { return fmt.Errorf("HTTP server already running on %s", h.endpoint) } - h.host, h.port = host, port + h.proto, h.host, h.port = proto, host, port h.endpoint = fmt.Sprintf("%s:%d", host, port) return nil } @@ -141,7 +142,7 @@ func (h *httpServer) start() error { } // Start the server. - listener, err := net.Listen("tcp", h.endpoint) + listener, err := net.Listen(h.proto, h.endpoint) if err != nil { // If the server fails to start, we need to clear out the RPC and WS // configuration so they can be configured another time. diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 4d10e61e2d..7d4bffb4e4 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -246,7 +246,7 @@ func createAndStartServer(t *testing.T, conf *httpConfig, ws bool, wsConf *wsCon if ws { assert.NoError(t, srv.enableWS(nil, *wsConf)) } - assert.NoError(t, srv.setListenAddr("localhost", 0)) + assert.NoError(t, srv.setListenAddr("tcp", "localhost", 0)) assert.NoError(t, srv.start()) return srv }