aboutsummaryrefslogtreecommitdiffstats
path: root/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'rpc')
-rw-r--r--rpc/http.go21
-rw-r--r--rpc/types.go67
2 files changed, 86 insertions, 2 deletions
diff --git a/rpc/http.go b/rpc/http.go
index 790442a28..61f8da549 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "net"
"net/http"
"github.com/ethereum/go-ethereum/logger"
@@ -15,6 +14,7 @@ import (
)
var rpclogger = logger.NewLogger("RPC")
+var rpclistener *ControllableTCPListener
const (
jsonrpcver = "2.0"
@@ -22,11 +22,17 @@ const (
)
func Start(pipe *xeth.XEth, config RpcConfig) error {
- l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort))
+ if rpclistener != nil { // listener already running
+ glog.Infoln("RPC listener already running")
+ return fmt.Errorf("RPC already running on %s", rpclistener.Addr().String())
+ }
+
+ l, err := NewControllableTCPListener(fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort))
if err != nil {
rpclogger.Errorf("Can't listen on %s:%d: %v", config.ListenAddress, config.ListenPort, err)
return err
}
+ rpclistener = l
var handler http.Handler
if len(config.CorsDomain) > 0 {
@@ -45,6 +51,17 @@ func Start(pipe *xeth.XEth, config RpcConfig) error {
return nil
}
+func Stop() error {
+ if rpclistener == nil { // listener not running
+ glog.Infoln("RPC listener not running")
+ return nil
+ }
+
+ rpclistener.Stop()
+ rpclistener = nil
+ return nil
+}
+
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
func JSONRPC(pipe *xeth.XEth) http.Handler {
api := NewEthereumApi(pipe)
diff --git a/rpc/types.go b/rpc/types.go
index bc9a46ed5..c7dc2cc9a 100644
--- a/rpc/types.go
+++ b/rpc/types.go
@@ -23,6 +23,10 @@ import (
"math/big"
"strings"
+ "errors"
+ "net"
+ "time"
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
@@ -257,3 +261,66 @@ type RpcErrorObject struct {
Message string `json:"message"`
// Data interface{} `json:"data"`
}
+
+type ListenerStoppedError struct {
+ msg string
+}
+
+func (self ListenerStoppedError) Timout() bool {
+ return false
+}
+
+func (self ListenerStoppedError) Temporary() bool {
+ return false
+}
+
+func (self ListenerStoppedError) Error() string {
+ return self.msg
+}
+
+type ControllableTCPListener struct {
+ *net.TCPListener
+ stop chan struct{}
+}
+
+var listenerStoppedError ListenerStoppedError
+
+func (self *ControllableTCPListener) Stop() {
+ close(self.stop)
+}
+
+func (self *ControllableTCPListener) Accept() (net.Conn, error) {
+ for {
+ self.SetDeadline(time.Now().Add(time.Duration(500 * time.Millisecond)))
+ c, err := self.TCPListener.AcceptTCP()
+
+ select {
+ case <-self.stop:
+ self.TCPListener.Close()
+ return nil, listenerStoppedError
+ default: // keep on going
+ }
+
+ if err != nil {
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() && netErr.Temporary() {
+ continue // regular timeout
+ }
+ }
+
+ return c, err
+ }
+}
+
+func NewControllableTCPListener(addr string) (*ControllableTCPListener, error) {
+ wl, err := net.Listen("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+
+ if tcpl, ok := wl.(*net.TCPListener); ok {
+ l := &ControllableTCPListener{tcpl, make(chan struct{})}
+ return l, nil
+ }
+
+ return nil, errors.New("Unable to create TCP listener for RPC")
+}