| 
									
										
										
										
											2015-01-13 09:13:43 -06:00
										 |  |  | /* | 
					
						
							|  |  |  |   This file is part of go-ethereum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |   the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |   (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |   GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |   along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | package rpc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-04-01 23:08:00 +02:00
										 |  |  | 	"encoding/binary" | 
					
						
							| 
									
										
										
										
											2015-05-12 17:04:56 +02:00
										 |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-01-29 12:01:51 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | type hexdata struct { | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	data  []byte | 
					
						
							|  |  |  | 	isNil bool | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 19:02:46 +02:00
										 |  |  | func (d *hexdata) String() string { | 
					
						
							|  |  |  | 	return "0x" + common.Bytes2Hex(d.data) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | func (d *hexdata) MarshalJSON() ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	if d.isNil { | 
					
						
							|  |  |  | 		return json.Marshal(nil) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 19:02:46 +02:00
										 |  |  | 	return json.Marshal(d.String()) | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newHexData(input interface{}) *hexdata { | 
					
						
							|  |  |  | 	d := new(hexdata) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 15:45:56 +02:00
										 |  |  | 	if input == nil { | 
					
						
							| 
									
										
										
										
											2015-04-04 15:09:30 +02:00
										 |  |  | 		d.isNil = true | 
					
						
							| 
									
										
										
										
											2015-04-01 17:49:22 +02:00
										 |  |  | 		return d | 
					
						
							| 
									
										
										
										
											2015-04-01 15:45:56 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 	switch input := input.(type) { | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case []byte: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = input | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case common.Hash: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = input.Bytes() | 
					
						
							| 
									
										
										
										
											2015-04-01 11:38:06 +02:00
										 |  |  | 	case *common.Hash: | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 		if input == nil { | 
					
						
							|  |  |  | 			d.isNil = true | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			d.data = input.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case common.Address: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = input.Bytes() | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	case *common.Address: | 
					
						
							|  |  |  | 		if input == nil { | 
					
						
							|  |  |  | 			d.isNil = true | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			d.data = input.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-02 12:31:10 +02:00
										 |  |  | 	case types.Bloom: | 
					
						
							|  |  |  | 		d.data = input.Bytes() | 
					
						
							|  |  |  | 	case *types.Bloom: | 
					
						
							|  |  |  | 		if input == nil { | 
					
						
							|  |  |  | 			d.isNil = true | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			d.data = input.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case *big.Int: | 
					
						
							| 
									
										
										
										
											2015-04-02 13:04:58 +02:00
										 |  |  | 		if input == nil { | 
					
						
							|  |  |  | 			d.isNil = true | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			d.data = input.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case int64: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = big.NewInt(input).Bytes() | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case uint64: | 
					
						
							| 
									
										
										
										
											2015-04-01 23:08:00 +02:00
										 |  |  | 		buff := make([]byte, 8) | 
					
						
							|  |  |  | 		binary.BigEndian.PutUint64(buff, input) | 
					
						
							|  |  |  | 		d.data = buff | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case int: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	case uint: | 
					
						
							| 
									
										
										
										
											2015-04-01 11:45:29 +02:00
										 |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							| 
									
										
										
										
											2015-04-02 12:31:10 +02:00
										 |  |  | 	case int8: | 
					
						
							|  |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							|  |  |  | 	case uint8: | 
					
						
							|  |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							|  |  |  | 	case int16: | 
					
						
							|  |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							|  |  |  | 	case uint16: | 
					
						
							| 
									
										
										
										
											2015-04-04 15:09:30 +02:00
										 |  |  | 		buff := make([]byte, 2) | 
					
						
							| 
									
										
										
										
											2015-04-02 12:52:25 +02:00
										 |  |  | 		binary.BigEndian.PutUint16(buff, input) | 
					
						
							|  |  |  | 		d.data = buff | 
					
						
							| 
									
										
										
										
											2015-04-02 12:31:10 +02:00
										 |  |  | 	case int32: | 
					
						
							|  |  |  | 		d.data = big.NewInt(int64(input)).Bytes() | 
					
						
							|  |  |  | 	case uint32: | 
					
						
							| 
									
										
										
										
											2015-04-04 15:09:30 +02:00
										 |  |  | 		buff := make([]byte, 4) | 
					
						
							| 
									
										
										
										
											2015-04-02 12:52:25 +02:00
										 |  |  | 		binary.BigEndian.PutUint32(buff, input) | 
					
						
							|  |  |  | 		d.data = buff | 
					
						
							| 
									
										
										
										
											2015-04-01 11:38:06 +02:00
										 |  |  | 	case string: // hexstring | 
					
						
							| 
									
										
										
										
											2015-05-12 17:04:56 +02:00
										 |  |  | 		// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded | 
					
						
							|  |  |  | 		bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x")) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			d.isNil = true | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			d.data = bytes | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-04-04 15:09:30 +02:00
										 |  |  | 		d.isNil = true | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return d | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type hexnum struct { | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	data  []byte | 
					
						
							|  |  |  | 	isNil bool | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 19:02:46 +02:00
										 |  |  | func (d *hexnum) String() string { | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	// Get hex string from bytes | 
					
						
							|  |  |  | 	out := common.Bytes2Hex(d.data) | 
					
						
							|  |  |  | 	// Trim leading 0s | 
					
						
							| 
									
										
										
										
											2015-04-02 12:30:42 +02:00
										 |  |  | 	out = strings.TrimLeft(out, "0") | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | 	// Output "0x0" when value is 0 | 
					
						
							|  |  |  | 	if len(out) == 0 { | 
					
						
							|  |  |  | 		out = "0" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 19:02:46 +02:00
										 |  |  | 	return "0x" + out | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *hexnum) MarshalJSON() ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-04-02 11:32:50 +02:00
										 |  |  | 	if d.isNil { | 
					
						
							|  |  |  | 		return json.Marshal(nil) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 19:02:46 +02:00
										 |  |  | 	return json.Marshal(d.String()) | 
					
						
							| 
									
										
										
										
											2015-03-31 17:39:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newHexNum(input interface{}) *hexnum { | 
					
						
							|  |  |  | 	d := new(hexnum) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	d.data = newHexData(input).data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return d | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-29 21:26:47 +02:00
										 |  |  | type RpcConfig struct { | 
					
						
							|  |  |  | 	ListenAddress string | 
					
						
							|  |  |  | 	ListenPort    uint | 
					
						
							|  |  |  | 	CorsDomain    string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 13:33:44 +01:00
										 |  |  | type InvalidTypeError struct { | 
					
						
							|  |  |  | 	method string | 
					
						
							|  |  |  | 	msg    string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *InvalidTypeError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("invalid type on field %s: %s", e.method, e.msg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewInvalidTypeError(method, msg string) *InvalidTypeError { | 
					
						
							|  |  |  | 	return &InvalidTypeError{ | 
					
						
							|  |  |  | 		method: method, | 
					
						
							|  |  |  | 		msg:    msg, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-12 19:07:03 -05:00
										 |  |  | type InsufficientParamsError struct { | 
					
						
							|  |  |  | 	have int | 
					
						
							|  |  |  | 	want int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *InsufficientParamsError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("insufficient params, want %d have %d", e.want, e.have) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewInsufficientParamsError(have int, want int) *InsufficientParamsError { | 
					
						
							|  |  |  | 	return &InsufficientParamsError{ | 
					
						
							|  |  |  | 		have: have, | 
					
						
							|  |  |  | 		want: want, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type NotImplementedError struct { | 
					
						
							|  |  |  | 	Method string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *NotImplementedError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("%s method not implemented", e.Method) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewNotImplementedError(method string) *NotImplementedError { | 
					
						
							|  |  |  | 	return &NotImplementedError{ | 
					
						
							|  |  |  | 		Method: method, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-11 11:53:53 +03:00
										 |  |  | type NotAvailableError struct { | 
					
						
							|  |  |  | 	Method string | 
					
						
							|  |  |  | 	Reason string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *NotAvailableError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("%s method not available: %s", e.Method, e.Reason) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewNotAvailableError(method string, reason string) *NotAvailableError { | 
					
						
							|  |  |  | 	return &NotAvailableError{ | 
					
						
							|  |  |  | 		Method: method, | 
					
						
							|  |  |  | 		Reason: reason, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-12 19:07:03 -05:00
										 |  |  | type DecodeParamError struct { | 
					
						
							|  |  |  | 	err string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *DecodeParamError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("could not decode, %s", e.err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewDecodeParamError(errstr string) error { | 
					
						
							|  |  |  | 	return &DecodeParamError{ | 
					
						
							|  |  |  | 		err: errstr, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ValidationError struct { | 
					
						
							|  |  |  | 	ParamName string | 
					
						
							|  |  |  | 	msg       string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *ValidationError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("%s not valid, %s", e.ParamName, e.msg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewValidationError(param string, msg string) error { | 
					
						
							|  |  |  | 	return &ValidationError{ | 
					
						
							|  |  |  | 		ParamName: param, | 
					
						
							|  |  |  | 		msg:       msg, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | type RpcRequest struct { | 
					
						
							| 
									
										
										
										
											2015-03-15 13:21:54 +07:00
										 |  |  | 	Id      interface{}     `json:"id"` | 
					
						
							|  |  |  | 	Jsonrpc string          `json:"jsonrpc"` | 
					
						
							| 
									
										
										
										
											2015-03-05 21:37:45 -06:00
										 |  |  | 	Method  string          `json:"method"` | 
					
						
							|  |  |  | 	Params  json.RawMessage `json:"params"` | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RpcSuccessResponse struct { | 
					
						
							| 
									
										
										
										
											2015-03-15 13:21:54 +07:00
										 |  |  | 	Id      interface{} `json:"id"` | 
					
						
							|  |  |  | 	Jsonrpc string      `json:"jsonrpc"` | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 	Result  interface{} `json:"result"` | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | type RpcErrorResponse struct { | 
					
						
							| 
									
										
										
										
											2015-03-15 13:21:54 +07:00
										 |  |  | 	Id      interface{}     `json:"id"` | 
					
						
							|  |  |  | 	Jsonrpc string          `json:"jsonrpc"` | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | 	Error   *RpcErrorObject `json:"error"` | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | type RpcErrorObject struct { | 
					
						
							|  |  |  | 	Code    int    `json:"code"` | 
					
						
							|  |  |  | 	Message string `json:"message"` | 
					
						
							|  |  |  | 	// Data    interface{} `json:"data"` | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | type listenerHasStoppedError struct { | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	msg string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func (self listenerHasStoppedError) Error() string { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	return self.msg | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | var listenerStoppedError = listenerHasStoppedError{"Listener stopped"} | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | // When https://github.com/golang/go/issues/4674 is fixed this could be replaced | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | type stoppableTCPListener struct { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	*net.TCPListener | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 	stop chan struct{} // closed when the listener must stop | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | // Wraps the default handler and checks if the RPC service was stopped. In that case it returns an | 
					
						
							|  |  |  | // error indicating that the service was stopped. This will only happen for connections which are | 
					
						
							|  |  |  | // kept open (HTTP keep-alive) when the RPC service was shutdown. | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func newStoppableHandler(h http.Handler, stop chan struct{}) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 		case <-stop: | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 			w.Header().Set("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 			jsonerr := &RpcErrorObject{-32603, "RPC service stopped"} | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 			send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr}) | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			h.ServeHTTP(w, r) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | // Stop the listener and all accepted and still active connections. | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func (self *stoppableTCPListener) Stop() { | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 	close(self.stop) | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func newStoppableTCPListener(addr string) (*stoppableTCPListener, error) { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	wl, err := net.Listen("tcp", addr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	if tcpl, ok := wl.(*net.TCPListener); ok { | 
					
						
							|  |  |  | 		stop := make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | 		l := &stoppableTCPListener{tcpl, stop} | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 		return l, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, errors.New("Unable to create TCP listener for RPC service") | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func (self *stoppableTCPListener) Accept() (net.Conn, error) { | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 		self.SetDeadline(time.Now().Add(time.Duration(1 * time.Second))) | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 		c, err := self.TCPListener.AcceptTCP() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 		case <-self.stop: | 
					
						
							|  |  |  | 			if c != nil { // accept timeout | 
					
						
							|  |  |  | 				c.Close() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 			self.TCPListener.Close() | 
					
						
							|  |  |  | 			return nil, listenerStoppedError | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if netErr, ok := err.(net.Error); ok && netErr.Timeout() && netErr.Temporary() { | 
					
						
							|  |  |  | 				continue // regular timeout | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | 		return &closableConnection{c, self.stop}, err | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | type closableConnection struct { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	*net.TCPConn | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 	closed chan struct{} | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-19 10:01:50 +02:00
										 |  |  | func (self *closableConnection) Read(b []byte) (n int, err error) { | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 	select { | 
					
						
							| 
									
										
										
										
											2015-04-19 09:55:41 +02:00
										 |  |  | 	case <-self.closed: | 
					
						
							| 
									
										
										
										
											2015-04-16 19:23:57 +02:00
										 |  |  | 		self.TCPConn.Close() | 
					
						
							|  |  |  | 		return 0, io.EOF | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return self.TCPConn.Read(b) | 
					
						
							| 
									
										
										
										
											2015-04-16 12:56:51 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |