github.com/lbryio/lbcd@v0.22.119/rpcclient/infrastructure.go (about)

     1  // Copyright (c) 2014-2017 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package rpcclient
     6  
     7  import (
     8  	"bytes"
     9  	"container/list"
    10  	"crypto/tls"
    11  	"crypto/x509"
    12  	"encoding/base64"
    13  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"io/ioutil"
    18  	"math"
    19  	"net"
    20  	"net/http"
    21  	"net/url"
    22  	"os"
    23  	"strings"
    24  	"sync"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	"github.com/btcsuite/go-socks/socks"
    29  	"github.com/btcsuite/websocket"
    30  	"github.com/lbryio/lbcd/btcjson"
    31  	"github.com/lbryio/lbcd/chaincfg"
    32  )
    33  
    34  var (
    35  	// ErrInvalidAuth is an error to describe the condition where the client
    36  	// is either unable to authenticate or the specified endpoint is
    37  	// incorrect.
    38  	ErrInvalidAuth = errors.New("authentication failure")
    39  
    40  	// ErrInvalidEndpoint is an error to describe the condition where the
    41  	// websocket handshake failed with the specified endpoint.
    42  	ErrInvalidEndpoint = errors.New("the endpoint either does not support " +
    43  		"websockets or does not exist")
    44  
    45  	// ErrClientNotConnected is an error to describe the condition where a
    46  	// websocket client has been created, but the connection was never
    47  	// established.  This condition differs from ErrClientDisconnect, which
    48  	// represents an established connection that was lost.
    49  	ErrClientNotConnected = errors.New("the client was never connected")
    50  
    51  	// ErrClientDisconnect is an error to describe the condition where the
    52  	// client has been disconnected from the RPC server.  When the
    53  	// DisableAutoReconnect option is not set, any outstanding futures
    54  	// when a client disconnect occurs will return this error as will
    55  	// any new requests.
    56  	ErrClientDisconnect = errors.New("the client has been disconnected")
    57  
    58  	// ErrClientShutdown is an error to describe the condition where the
    59  	// client is either already shutdown, or in the process of shutting
    60  	// down.  Any outstanding futures when a client shutdown occurs will
    61  	// return this error as will any new requests.
    62  	ErrClientShutdown = errors.New("the client has been shutdown")
    63  
    64  	// ErrNotWebsocketClient is an error to describe the condition of
    65  	// calling a Client method intended for a websocket client when the
    66  	// client has been configured to run in HTTP POST mode instead.
    67  	ErrNotWebsocketClient = errors.New("client is not configured for " +
    68  		"websockets")
    69  
    70  	// ErrClientAlreadyConnected is an error to describe the condition where
    71  	// a new client connection cannot be established due to a websocket
    72  	// client having already connected to the RPC server.
    73  	ErrClientAlreadyConnected = errors.New("websocket client has already " +
    74  		"connected")
    75  )
    76  
    77  const (
    78  	// sendBufferSize is the number of elements the websocket send channel
    79  	// can queue before blocking.
    80  	sendBufferSize = 50
    81  
    82  	// sendPostBufferSize is the number of elements the HTTP POST send
    83  	// channel can queue before blocking.
    84  	sendPostBufferSize = 100
    85  
    86  	// connectionRetryInterval is the amount of time to wait in between
    87  	// retries when automatically reconnecting to an RPC server.
    88  	connectionRetryInterval = time.Second * 5
    89  
    90  	// requestRetryInterval is the initial amount of time to wait in between
    91  	// retries when sending HTTP POST requests.
    92  	requestRetryInterval = time.Millisecond * 500
    93  )
    94  
    95  // jsonRequest holds information about a json request that is used to properly
    96  // detect, interpret, and deliver a reply to it.
    97  type jsonRequest struct {
    98  	id             uint64
    99  	method         string
   100  	cmd            interface{}
   101  	marshalledJSON []byte
   102  	responseChan   chan *Response
   103  }
   104  
   105  // BackendVersion represents the version of the backend the client is currently
   106  // connected to.
   107  type BackendVersion uint8
   108  
   109  const (
   110  	// BitcoindPre19 represents a bitcoind version before 0.19.0.
   111  	BitcoindPre19 BackendVersion = iota
   112  
   113  	// BitcoindPost19 represents a bitcoind version equal to or greater than
   114  	// 0.19.0.
   115  	BitcoindPost19
   116  
   117  	// Lbcd represents a catch-all lbcd version.
   118  	Lbcd
   119  )
   120  
   121  // Client represents a Bitcoin RPC client which allows easy access to the
   122  // various RPC methods available on a Bitcoin RPC server.  Each of the wrapper
   123  // functions handle the details of converting the passed and return types to and
   124  // from the underlying JSON types which are required for the JSON-RPC
   125  // invocations
   126  //
   127  // The client provides each RPC in both synchronous (blocking) and asynchronous
   128  // (non-blocking) forms.  The asynchronous forms are based on the concept of
   129  // futures where they return an instance of a type that promises to deliver the
   130  // result of the invocation at some future time.  Invoking the Receive method on
   131  // the returned future will block until the result is available if it's not
   132  // already.
   133  type Client struct {
   134  	id uint64 // atomic, so must stay 64-bit aligned
   135  
   136  	// config holds the connection configuration assoiated with this client.
   137  	config *ConnConfig
   138  
   139  	// chainParams holds the params for the chain that this client is using,
   140  	// and is used for many wallet methods.
   141  	chainParams *chaincfg.Params
   142  
   143  	// wsConn is the underlying websocket connection when not in HTTP POST
   144  	// mode.
   145  	wsConn *websocket.Conn
   146  
   147  	// httpClient is the underlying HTTP client to use when running in HTTP
   148  	// POST mode.
   149  	httpClient *http.Client
   150  
   151  	// backendVersion is the version of the backend the client is currently
   152  	// connected to. This should be retrieved through GetVersion.
   153  	backendVersionMu sync.Mutex
   154  	backendVersion   *BackendVersion
   155  
   156  	// mtx is a mutex to protect access to connection related fields.
   157  	mtx sync.Mutex
   158  
   159  	// disconnected indicated whether or not the server is disconnected.
   160  	disconnected bool
   161  
   162  	// whether or not to batch requests, false unless changed by Batch()
   163  	batch     bool
   164  	batchList *list.List
   165  
   166  	// retryCount holds the number of times the client has tried to
   167  	// reconnect to the RPC server.
   168  	retryCount int64
   169  
   170  	// Track command and their response channels by ID.
   171  	requestLock sync.Mutex
   172  	requestMap  map[uint64]*list.Element
   173  	requestList *list.List
   174  
   175  	// Notifications.
   176  	ntfnHandlers  *NotificationHandlers
   177  	ntfnStateLock sync.Mutex
   178  	ntfnState     *notificationState
   179  
   180  	// Networking infrastructure.
   181  	sendChan        chan []byte
   182  	sendPostChan    chan *jsonRequest
   183  	connEstablished chan struct{}
   184  	disconnect      chan struct{}
   185  	shutdown        chan struct{}
   186  	wg              sync.WaitGroup
   187  }
   188  
   189  // NextID returns the next id to be used when sending a JSON-RPC message.  This
   190  // ID allows responses to be associated with particular requests per the
   191  // JSON-RPC specification.  Typically the consumer of the client does not need
   192  // to call this function, however, if a custom request is being created and used
   193  // this function should be used to ensure the ID is unique amongst all requests
   194  // being made.
   195  func (c *Client) NextID() uint64 {
   196  	return atomic.AddUint64(&c.id, 1)
   197  }
   198  
   199  // addRequest associates the passed jsonRequest with its id.  This allows the
   200  // response from the remote server to be unmarshalled to the appropriate type
   201  // and sent to the specified channel when it is received.
   202  //
   203  // If the client has already begun shutting down, ErrClientShutdown is returned
   204  // and the request is not added.
   205  //
   206  // This function is safe for concurrent access.
   207  func (c *Client) addRequest(jReq *jsonRequest) error {
   208  	c.requestLock.Lock()
   209  	defer c.requestLock.Unlock()
   210  
   211  	// A non-blocking read of the shutdown channel with the request lock
   212  	// held avoids adding the request to the client's internal data
   213  	// structures if the client is in the process of shutting down (and
   214  	// has not yet grabbed the request lock), or has finished shutdown
   215  	// already (responding to each outstanding request with
   216  	// ErrClientShutdown).
   217  	select {
   218  	case <-c.shutdown:
   219  		return ErrClientShutdown
   220  	default:
   221  	}
   222  
   223  	if !c.batch {
   224  		element := c.requestList.PushBack(jReq)
   225  		c.requestMap[jReq.id] = element
   226  	} else {
   227  		element := c.batchList.PushBack(jReq)
   228  		c.requestMap[jReq.id] = element
   229  	}
   230  	return nil
   231  }
   232  
   233  // removeRequest returns and removes the jsonRequest which contains the response
   234  // channel and original method associated with the passed id or nil if there is
   235  // no association.
   236  //
   237  // This function is safe for concurrent access.
   238  func (c *Client) removeRequest(id uint64) *jsonRequest {
   239  	c.requestLock.Lock()
   240  	defer c.requestLock.Unlock()
   241  
   242  	element := c.requestMap[id]
   243  	if element != nil {
   244  		delete(c.requestMap, id)
   245  		request := c.requestList.Remove(element).(*jsonRequest)
   246  		return request
   247  	}
   248  
   249  	return nil
   250  }
   251  
   252  // removeAllRequests removes all the jsonRequests which contain the response
   253  // channels for outstanding requests.
   254  //
   255  // This function MUST be called with the request lock held.
   256  func (c *Client) removeAllRequests() {
   257  	c.requestMap = make(map[uint64]*list.Element)
   258  	c.requestList.Init()
   259  }
   260  
   261  // trackRegisteredNtfns examines the passed command to see if it is one of
   262  // the notification commands and updates the notification state that is used
   263  // to automatically re-establish registered notifications on reconnects.
   264  func (c *Client) trackRegisteredNtfns(cmd interface{}) {
   265  	// Nothing to do if the caller is not interested in notifications.
   266  	if c.ntfnHandlers == nil {
   267  		return
   268  	}
   269  
   270  	c.ntfnStateLock.Lock()
   271  	defer c.ntfnStateLock.Unlock()
   272  
   273  	switch bcmd := cmd.(type) {
   274  	case *btcjson.NotifyBlocksCmd:
   275  		c.ntfnState.notifyBlocks = true
   276  
   277  	case *btcjson.NotifyNewTransactionsCmd:
   278  		if bcmd.Verbose != nil && *bcmd.Verbose {
   279  			c.ntfnState.notifyNewTxVerbose = true
   280  		} else {
   281  			c.ntfnState.notifyNewTx = true
   282  
   283  		}
   284  
   285  	case *btcjson.NotifySpentCmd:
   286  		for _, op := range bcmd.OutPoints {
   287  			c.ntfnState.notifySpent[op] = struct{}{}
   288  		}
   289  
   290  	case *btcjson.NotifyReceivedCmd:
   291  		for _, addr := range bcmd.Addresses {
   292  			c.ntfnState.notifyReceived[addr] = struct{}{}
   293  		}
   294  	}
   295  }
   296  
   297  // FutureGetBulkResult waits for the responses promised by the future
   298  // and returns them in a channel
   299  type FutureGetBulkResult chan *Response
   300  
   301  // Receive waits for the response promised by the future and returns an map
   302  // of results by request id
   303  func (r FutureGetBulkResult) Receive() (BulkResult, error) {
   304  	m := make(BulkResult)
   305  	res, err := ReceiveFuture(r)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  	var arr []IndividualBulkResult
   310  	err = json.Unmarshal(res, &arr)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	for _, results := range arr {
   316  		m[results.Id] = results
   317  	}
   318  
   319  	return m, nil
   320  }
   321  
   322  // IndividualBulkResult represents one result
   323  // from a bulk json rpc api
   324  type IndividualBulkResult struct {
   325  	Result interface{}       `json:"result"`
   326  	Error  *btcjson.RPCError `json:"error"`
   327  	Id     uint64            `json:"id"`
   328  }
   329  
   330  type BulkResult = map[uint64]IndividualBulkResult
   331  
   332  // inMessage is the first type that an incoming message is unmarshaled
   333  // into. It supports both requests (for notification support) and
   334  // responses.  The partially-unmarshaled message is a notification if
   335  // the embedded ID (from the response) is nil.  Otherwise, it is a
   336  // response.
   337  type inMessage struct {
   338  	ID *float64 `json:"id"`
   339  	*rawNotification
   340  	*rawResponse
   341  }
   342  
   343  // rawNotification is a partially-unmarshaled JSON-RPC notification.
   344  type rawNotification struct {
   345  	Method string            `json:"method"`
   346  	Params []json.RawMessage `json:"params"`
   347  }
   348  
   349  // rawResponse is a partially-unmarshaled JSON-RPC response.  For this
   350  // to be valid (according to JSON-RPC 1.0 spec), ID may not be nil.
   351  type rawResponse struct {
   352  	Result json.RawMessage   `json:"result"`
   353  	Error  *btcjson.RPCError `json:"error"`
   354  }
   355  
   356  // Response is the raw bytes of a JSON-RPC result, or the error if the response
   357  // error object was non-null.
   358  type Response struct {
   359  	result []byte
   360  	err    error
   361  }
   362  
   363  // result checks whether the unmarshaled response contains a non-nil error,
   364  // returning an unmarshaled btcjson.RPCError (or an unmarshaling error) if so.
   365  // If the response is not an error, the raw bytes of the request are
   366  // returned for further unmashaling into specific result types.
   367  func (r rawResponse) result() (result []byte, err error) {
   368  	if r.Error != nil {
   369  		return nil, r.Error
   370  	}
   371  	return r.Result, nil
   372  }
   373  
   374  // handleMessage is the main handler for incoming notifications and responses.
   375  func (c *Client) handleMessage(msg []byte) {
   376  	// Attempt to unmarshal the message as either a notification or
   377  	// response.
   378  	var in inMessage
   379  	in.rawResponse = new(rawResponse)
   380  	in.rawNotification = new(rawNotification)
   381  	err := json.Unmarshal(msg, &in)
   382  	if err != nil {
   383  		log.Warnf("Remote server sent invalid message: %v", err)
   384  		return
   385  	}
   386  
   387  	// JSON-RPC 1.0 notifications are requests with a null id.
   388  	if in.ID == nil {
   389  		ntfn := in.rawNotification
   390  		if ntfn == nil {
   391  			log.Warn("Malformed notification: missing " +
   392  				"method and parameters")
   393  			return
   394  		}
   395  		if ntfn.Method == "" {
   396  			log.Warn("Malformed notification: missing method")
   397  			return
   398  		}
   399  		// params are not optional: nil isn't valid (but len == 0 is)
   400  		if ntfn.Params == nil {
   401  			log.Warn("Malformed notification: missing params")
   402  			return
   403  		}
   404  		// Deliver the notification.
   405  		log.Tracef("Received notification [%s]", in.Method)
   406  		c.handleNotification(in.rawNotification)
   407  		return
   408  	}
   409  
   410  	// ensure that in.ID can be converted to an integer without loss of precision
   411  	if *in.ID < 0 || *in.ID != math.Trunc(*in.ID) {
   412  		log.Warn("Malformed response: invalid identifier")
   413  		return
   414  	}
   415  
   416  	if in.rawResponse == nil {
   417  		log.Warn("Malformed response: missing result and error")
   418  		return
   419  	}
   420  
   421  	id := uint64(*in.ID)
   422  	log.Tracef("Received response for id %d (result %s)", id, in.Result)
   423  	request := c.removeRequest(id)
   424  
   425  	// Nothing more to do if there is no request associated with this reply.
   426  	if request == nil || request.responseChan == nil {
   427  		log.Warnf("Received unexpected reply: %s (id %d)", in.Result,
   428  			id)
   429  		return
   430  	}
   431  
   432  	// Since the command was successful, examine it to see if it's a
   433  	// notification, and if is, add it to the notification state so it
   434  	// can automatically be re-established on reconnect.
   435  	c.trackRegisteredNtfns(request.cmd)
   436  
   437  	// Deliver the response.
   438  	result, err := in.rawResponse.result()
   439  	request.responseChan <- &Response{result: result, err: err}
   440  }
   441  
   442  // shouldLogReadError returns whether or not the passed error, which is expected
   443  // to have come from reading from the websocket connection in wsInHandler,
   444  // should be logged.
   445  func (c *Client) shouldLogReadError(err error) bool {
   446  	// No logging when the connetion is being forcibly disconnected.
   447  	select {
   448  	case <-c.shutdown:
   449  		return false
   450  	default:
   451  	}
   452  
   453  	// No logging when the connection has been disconnected.
   454  	if err == io.EOF {
   455  		return false
   456  	}
   457  	if opErr, ok := err.(*net.OpError); ok && !opErr.Temporary() {
   458  		return false
   459  	}
   460  
   461  	return true
   462  }
   463  
   464  // wsInHandler handles all incoming messages for the websocket connection
   465  // associated with the client.  It must be run as a goroutine.
   466  func (c *Client) wsInHandler() {
   467  out:
   468  	for {
   469  		// Break out of the loop once the shutdown channel has been
   470  		// closed.  Use a non-blocking select here so we fall through
   471  		// otherwise.
   472  		select {
   473  		case <-c.shutdown:
   474  			break out
   475  		default:
   476  		}
   477  
   478  		_, msg, err := c.wsConn.ReadMessage()
   479  		if err != nil {
   480  			// Log the error if it's not due to disconnecting.
   481  			if c.shouldLogReadError(err) {
   482  				log.Errorf("Websocket receive error from "+
   483  					"%s: %v", c.config.Host, err)
   484  			}
   485  			break out
   486  		}
   487  		c.handleMessage(msg)
   488  	}
   489  
   490  	// Ensure the connection is closed.
   491  	c.Disconnect()
   492  	c.wg.Done()
   493  	log.Tracef("RPC client input handler done for %s", c.config.Host)
   494  }
   495  
   496  // disconnectChan returns a copy of the current disconnect channel.  The channel
   497  // is read protected by the client mutex, and is safe to call while the channel
   498  // is being reassigned during a reconnect.
   499  func (c *Client) disconnectChan() <-chan struct{} {
   500  	c.mtx.Lock()
   501  	ch := c.disconnect
   502  	c.mtx.Unlock()
   503  	return ch
   504  }
   505  
   506  // wsOutHandler handles all outgoing messages for the websocket connection.  It
   507  // uses a buffered channel to serialize output messages while allowing the
   508  // sender to continue running asynchronously.  It must be run as a goroutine.
   509  func (c *Client) wsOutHandler() {
   510  out:
   511  	for {
   512  		// Send any messages ready for send until the client is
   513  		// disconnected closed.
   514  		select {
   515  		case msg := <-c.sendChan:
   516  			err := c.wsConn.WriteMessage(websocket.TextMessage, msg)
   517  			if err != nil {
   518  				c.Disconnect()
   519  				break out
   520  			}
   521  
   522  		case <-c.disconnectChan():
   523  			break out
   524  		}
   525  	}
   526  
   527  	// Drain any channels before exiting so nothing is left waiting around
   528  	// to send.
   529  cleanup:
   530  	for {
   531  		select {
   532  		case <-c.sendChan:
   533  		default:
   534  			break cleanup
   535  		}
   536  	}
   537  	c.wg.Done()
   538  	log.Tracef("RPC client output handler done for %s", c.config.Host)
   539  }
   540  
   541  // sendMessage sends the passed JSON to the connected server using the
   542  // websocket connection.  It is backed by a buffered channel, so it will not
   543  // block until the send channel is full.
   544  func (c *Client) sendMessage(marshalledJSON []byte) {
   545  	// Don't send the message if disconnected.
   546  	select {
   547  	case c.sendChan <- marshalledJSON:
   548  	case <-c.disconnectChan():
   549  		return
   550  	}
   551  }
   552  
   553  // reregisterNtfns creates and sends commands needed to re-establish the current
   554  // notification state associated with the client.  It should only be called on
   555  // on reconnect by the resendRequests function.
   556  func (c *Client) reregisterNtfns() error {
   557  	// Nothing to do if the caller is not interested in notifications.
   558  	if c.ntfnHandlers == nil {
   559  		return nil
   560  	}
   561  
   562  	// In order to avoid holding the lock on the notification state for the
   563  	// entire time of the potentially long running RPCs issued below, make a
   564  	// copy of it and work from that.
   565  	//
   566  	// Also, other commands will be running concurrently which could modify
   567  	// the notification state (while not under the lock of course) which
   568  	// also register it with the remote RPC server, so this prevents double
   569  	// registrations.
   570  	c.ntfnStateLock.Lock()
   571  	stateCopy := c.ntfnState.Copy()
   572  	c.ntfnStateLock.Unlock()
   573  
   574  	// Reregister notifyblocks if needed.
   575  	if stateCopy.notifyBlocks {
   576  		log.Debugf("Reregistering [notifyblocks]")
   577  		if err := c.NotifyBlocks(); err != nil {
   578  			return err
   579  		}
   580  	}
   581  
   582  	// Reregister notifynewtransactions if needed.
   583  	if stateCopy.notifyNewTx || stateCopy.notifyNewTxVerbose {
   584  		log.Debugf("Reregistering [notifynewtransactions] (verbose=%v)",
   585  			stateCopy.notifyNewTxVerbose)
   586  		err := c.NotifyNewTransactions(stateCopy.notifyNewTxVerbose)
   587  		if err != nil {
   588  			return err
   589  		}
   590  	}
   591  
   592  	// Reregister the combination of all previously registered notifyspent
   593  	// outpoints in one command if needed.
   594  	nslen := len(stateCopy.notifySpent)
   595  	if nslen > 0 {
   596  		outpoints := make([]btcjson.OutPoint, 0, nslen)
   597  		for op := range stateCopy.notifySpent {
   598  			outpoints = append(outpoints, op)
   599  		}
   600  		log.Debugf("Reregistering [notifyspent] outpoints: %v", outpoints)
   601  		if err := c.notifySpentInternal(outpoints).Receive(); err != nil {
   602  			return err
   603  		}
   604  	}
   605  
   606  	// Reregister the combination of all previously registered
   607  	// notifyreceived addresses in one command if needed.
   608  	nrlen := len(stateCopy.notifyReceived)
   609  	if nrlen > 0 {
   610  		addresses := make([]string, 0, nrlen)
   611  		for addr := range stateCopy.notifyReceived {
   612  			addresses = append(addresses, addr)
   613  		}
   614  		log.Debugf("Reregistering [notifyreceived] addresses: %v", addresses)
   615  		if err := c.notifyReceivedInternal(addresses).Receive(); err != nil {
   616  			return err
   617  		}
   618  	}
   619  
   620  	return nil
   621  }
   622  
   623  // ignoreResends is a set of all methods for requests that are "long running"
   624  // are not be reissued by the client on reconnect.
   625  var ignoreResends = map[string]struct{}{
   626  	"rescan": {},
   627  }
   628  
   629  // resendRequests resends any requests that had not completed when the client
   630  // disconnected.  It is intended to be called once the client has reconnected as
   631  // a separate goroutine.
   632  func (c *Client) resendRequests() {
   633  	// Set the notification state back up.  If anything goes wrong,
   634  	// disconnect the client.
   635  	if err := c.reregisterNtfns(); err != nil {
   636  		log.Warnf("Unable to re-establish notification state: %v", err)
   637  		c.Disconnect()
   638  		return
   639  	}
   640  
   641  	// Since it's possible to block on send and more requests might be
   642  	// added by the caller while resending, make a copy of all of the
   643  	// requests that need to be resent now and work from the copy.  This
   644  	// also allows the lock to be released quickly.
   645  	c.requestLock.Lock()
   646  	resendReqs := make([]*jsonRequest, 0, c.requestList.Len())
   647  	var nextElem *list.Element
   648  	for e := c.requestList.Front(); e != nil; e = nextElem {
   649  		nextElem = e.Next()
   650  
   651  		jReq := e.Value.(*jsonRequest)
   652  		if _, ok := ignoreResends[jReq.method]; ok {
   653  			// If a request is not sent on reconnect, remove it
   654  			// from the request structures, since no reply is
   655  			// expected.
   656  			delete(c.requestMap, jReq.id)
   657  			c.requestList.Remove(e)
   658  		} else {
   659  			resendReqs = append(resendReqs, jReq)
   660  		}
   661  	}
   662  	c.requestLock.Unlock()
   663  
   664  	for _, jReq := range resendReqs {
   665  		// Stop resending commands if the client disconnected again
   666  		// since the next reconnect will handle them.
   667  		if c.Disconnected() {
   668  			return
   669  		}
   670  
   671  		log.Tracef("Sending command [%s] with id %d", jReq.method,
   672  			jReq.id)
   673  		c.sendMessage(jReq.marshalledJSON)
   674  	}
   675  }
   676  
   677  // wsReconnectHandler listens for client disconnects and automatically tries
   678  // to reconnect with retry interval that scales based on the number of retries.
   679  // It also resends any commands that had not completed when the client
   680  // disconnected so the disconnect/reconnect process is largely transparent to
   681  // the caller.  This function is not run when the DisableAutoReconnect config
   682  // options is set.
   683  //
   684  // This function must be run as a goroutine.
   685  func (c *Client) wsReconnectHandler() {
   686  out:
   687  	for {
   688  		select {
   689  		case <-c.disconnect:
   690  			// On disconnect, fallthrough to reestablish the
   691  			// connection.
   692  
   693  		case <-c.shutdown:
   694  			break out
   695  		}
   696  
   697  	reconnect:
   698  		for {
   699  			select {
   700  			case <-c.shutdown:
   701  				break out
   702  			default:
   703  			}
   704  
   705  			wsConn, err := dial(c.config)
   706  			if err != nil {
   707  				c.retryCount++
   708  				log.Infof("Failed to connect to %s: %v",
   709  					c.config.Host, err)
   710  
   711  				// Scale the retry interval by the number of
   712  				// retries so there is a backoff up to a max
   713  				// of 1 minute.
   714  				scaledInterval := connectionRetryInterval.Nanoseconds() * c.retryCount
   715  				scaledDuration := time.Duration(scaledInterval)
   716  				if scaledDuration > time.Minute {
   717  					scaledDuration = time.Minute
   718  				}
   719  				log.Infof("Retrying connection to %s in "+
   720  					"%s", c.config.Host, scaledDuration)
   721  				time.Sleep(scaledDuration)
   722  				continue reconnect
   723  			}
   724  
   725  			log.Infof("Reestablished connection to RPC server %s",
   726  				c.config.Host)
   727  
   728  			// Reset the version in case the backend was
   729  			// disconnected due to an upgrade.
   730  			c.backendVersionMu.Lock()
   731  			c.backendVersion = nil
   732  			c.backendVersionMu.Unlock()
   733  
   734  			// Reset the connection state and signal the reconnect
   735  			// has happened.
   736  			c.wsConn = wsConn
   737  			c.retryCount = 0
   738  
   739  			c.mtx.Lock()
   740  			c.disconnect = make(chan struct{})
   741  			c.disconnected = false
   742  			c.mtx.Unlock()
   743  
   744  			// Start processing input and output for the
   745  			// new connection.
   746  			c.start()
   747  
   748  			// Reissue pending requests in another goroutine since
   749  			// the send can block.
   750  			go c.resendRequests()
   751  
   752  			// Break out of the reconnect loop back to wait for
   753  			// disconnect again.
   754  			break reconnect
   755  		}
   756  	}
   757  	c.wg.Done()
   758  	log.Tracef("RPC client reconnect handler done for %s", c.config.Host)
   759  }
   760  
   761  // handleSendPostMessage handles performing the passed HTTP request, reading the
   762  // result, unmarshalling it, and delivering the unmarshalled result to the
   763  // provided response channel.
   764  func (c *Client) handleSendPostMessage(jReq *jsonRequest) {
   765  	protocol := "http"
   766  	if !c.config.DisableTLS {
   767  		protocol = "https"
   768  	}
   769  	url := protocol + "://" + c.config.Host
   770  
   771  	var err error
   772  	var backoff time.Duration
   773  	var httpResponse *http.Response
   774  	tries := 10
   775  	for i := 0; tries == 0 || i < tries; i++ {
   776  		bodyReader := bytes.NewReader(jReq.marshalledJSON)
   777  		var httpReq *http.Request
   778  		httpReq, err = http.NewRequest("POST", url, bodyReader)
   779  		if err != nil {
   780  			jReq.responseChan <- &Response{result: nil, err: err}
   781  			return
   782  		}
   783  		httpReq.Close = true
   784  		httpReq.Header.Set("Content-Type", "application/json")
   785  		for key, value := range c.config.ExtraHeaders {
   786  			httpReq.Header.Set(key, value)
   787  		}
   788  
   789  		// Configure basic access authorization.
   790  		var user, pass string
   791  		user, pass, err = c.config.getAuth()
   792  		if err != nil {
   793  			jReq.responseChan <- &Response{result: nil, err: err}
   794  			return
   795  		}
   796  		httpReq.SetBasicAuth(user, pass)
   797  
   798  		httpResponse, err = c.httpClient.Do(httpReq)
   799  		if err != nil {
   800  			backoff = requestRetryInterval * time.Duration(i+1)
   801  			if backoff > time.Minute {
   802  				backoff = time.Minute
   803  			}
   804  			log.Debugf("Failed command [%s] with id %d attempt %d. Retrying in %v... \n", jReq.method, jReq.id, i, backoff)
   805  			time.Sleep(backoff)
   806  			continue
   807  		}
   808  		defer httpResponse.Body.Close()
   809  		break
   810  	}
   811  	if err != nil {
   812  		jReq.responseChan <- &Response{err: err}
   813  		return
   814  	}
   815  
   816  	// Read the raw bytes from the response.
   817  	respBytes, err := ioutil.ReadAll(httpResponse.Body)
   818  	if err != nil {
   819  		err = fmt.Errorf("error reading json reply: %v", err)
   820  		jReq.responseChan <- &Response{err: err}
   821  		return
   822  	}
   823  
   824  	// Try to unmarshal the response as a regular JSON-RPC response.
   825  	var resp rawResponse
   826  	var batchResponse json.RawMessage
   827  	if c.batch {
   828  		err = json.Unmarshal(respBytes, &batchResponse)
   829  	} else {
   830  		err = json.Unmarshal(respBytes, &resp)
   831  	}
   832  	if err != nil {
   833  		// When the response itself isn't a valid JSON-RPC response
   834  		// return an error which includes the HTTP status code and raw
   835  		// response bytes.
   836  		err = fmt.Errorf("status code: %d, response: %q",
   837  			httpResponse.StatusCode, string(respBytes))
   838  		jReq.responseChan <- &Response{err: err}
   839  		return
   840  	}
   841  	var res []byte
   842  	if c.batch {
   843  		// errors must be dealt with downstream since a whole request cannot
   844  		// "error out" other than through the status code error handled above
   845  		res, err = batchResponse, nil
   846  	} else {
   847  		res, err = resp.result()
   848  	}
   849  	jReq.responseChan <- &Response{result: res, err: err}
   850  }
   851  
   852  // sendPostHandler handles all outgoing messages when the client is running
   853  // in HTTP POST mode.  It uses a buffered channel to serialize output messages
   854  // while allowing the sender to continue running asynchronously.  It must be run
   855  // as a goroutine.
   856  func (c *Client) sendPostHandler() {
   857  out:
   858  	for {
   859  		// Send any messages ready for send until the shutdown channel
   860  		// is closed.
   861  		select {
   862  		case jReq := <-c.sendPostChan:
   863  			c.handleSendPostMessage(jReq)
   864  
   865  		case <-c.shutdown:
   866  			break out
   867  		}
   868  	}
   869  
   870  	// Drain any wait channels before exiting so nothing is left waiting
   871  	// around to send.
   872  cleanup:
   873  	for {
   874  		select {
   875  		case jReq := <-c.sendPostChan:
   876  			jReq.responseChan <- &Response{
   877  				result: nil,
   878  				err:    ErrClientShutdown,
   879  			}
   880  
   881  		default:
   882  			break cleanup
   883  		}
   884  	}
   885  	c.wg.Done()
   886  	log.Tracef("RPC client send handler done for %s", c.config.Host)
   887  
   888  }
   889  
   890  // sendPostRequest sends the passed HTTP request to the RPC server using the
   891  // HTTP client associated with the client.  It is backed by a buffered channel,
   892  // so it will not block until the send channel is full.
   893  func (c *Client) sendPostRequest(jReq *jsonRequest) {
   894  	// Don't send the message if shutting down.
   895  	select {
   896  	case <-c.shutdown:
   897  		jReq.responseChan <- &Response{result: nil, err: ErrClientShutdown}
   898  	default:
   899  	}
   900  
   901  	log.Tracef("Sending command [%s] with id %d", jReq.method, jReq.id)
   902  
   903  	c.sendPostChan <- jReq
   904  }
   905  
   906  // newFutureError returns a new future result channel that already has the
   907  // passed error waitin on the channel with the reply set to nil.  This is useful
   908  // to easily return errors from the various Async functions.
   909  func newFutureError(err error) chan *Response {
   910  	responseChan := make(chan *Response, 1)
   911  	responseChan <- &Response{err: err}
   912  	return responseChan
   913  }
   914  
   915  // ReceiveFuture receives from the passed futureResult channel to extract a
   916  // reply or any errors.  The examined errors include an error in the
   917  // futureResult and the error in the reply from the server.  This will block
   918  // until the result is available on the passed channel.
   919  func ReceiveFuture(f chan *Response) ([]byte, error) {
   920  	// Wait for a response on the returned channel.
   921  	r := <-f
   922  	return r.result, r.err
   923  }
   924  
   925  // sendRequest sends the passed json request to the associated server using the
   926  // provided response channel for the reply.  It handles both websocket and HTTP
   927  // POST mode depending on the configuration of the client.
   928  func (c *Client) sendRequest(jReq *jsonRequest) {
   929  	// Choose which marshal and send function to use depending on whether
   930  	// the client running in HTTP POST mode or not.  When running in HTTP
   931  	// POST mode, the command is issued via an HTTP client.  Otherwise,
   932  	// the command is issued via the asynchronous websocket channels.
   933  	if c.config.HTTPPostMode {
   934  		if c.batch {
   935  			if err := c.addRequest(jReq); err != nil {
   936  				log.Warn(err)
   937  			}
   938  		} else {
   939  			c.sendPostRequest(jReq)
   940  		}
   941  		return
   942  	}
   943  
   944  	// Check whether the websocket connection has never been established,
   945  	// in which case the handler goroutines are not running.
   946  	select {
   947  	case <-c.connEstablished:
   948  	default:
   949  		jReq.responseChan <- &Response{err: ErrClientNotConnected}
   950  		return
   951  	}
   952  
   953  	// Add the request to the internal tracking map so the response from the
   954  	// remote server can be properly detected and routed to the response
   955  	// channel.  Then send the marshalled request via the websocket
   956  	// connection.
   957  	if err := c.addRequest(jReq); err != nil {
   958  		jReq.responseChan <- &Response{err: err}
   959  		return
   960  	}
   961  	log.Tracef("Sending command [%s] with id %d", jReq.method, jReq.id)
   962  	c.sendMessage(jReq.marshalledJSON)
   963  }
   964  
   965  // SendCmd sends the passed command to the associated server and returns a
   966  // response channel on which the reply will be delivered at some point in the
   967  // future.  It handles both websocket and HTTP POST mode depending on the
   968  // configuration of the client.
   969  func (c *Client) SendCmd(cmd interface{}) chan *Response {
   970  	rpcVersion := btcjson.RpcVersion1
   971  	if c.batch {
   972  		rpcVersion = btcjson.RpcVersion2
   973  	}
   974  	// Get the method associated with the command.
   975  	method, err := btcjson.CmdMethod(cmd)
   976  	if err != nil {
   977  		return newFutureError(err)
   978  	}
   979  
   980  	// Marshal the command.
   981  	id := c.NextID()
   982  	marshalledJSON, err := btcjson.MarshalCmd(rpcVersion, id, cmd)
   983  	if err != nil {
   984  		return newFutureError(err)
   985  	}
   986  
   987  	// Generate the request and send it along with a channel to respond on.
   988  	responseChan := make(chan *Response, 1)
   989  	jReq := &jsonRequest{
   990  		id:             id,
   991  		method:         method,
   992  		cmd:            cmd,
   993  		marshalledJSON: marshalledJSON,
   994  		responseChan:   responseChan,
   995  	}
   996  
   997  	c.sendRequest(jReq)
   998  
   999  	return responseChan
  1000  }
  1001  
  1002  // sendCmdAndWait sends the passed command to the associated server, waits
  1003  // for the reply, and returns the result from it.  It will return the error
  1004  // field in the reply if there is one.
  1005  func (c *Client) sendCmdAndWait(cmd interface{}) (interface{}, error) {
  1006  	// Marshal the command to JSON-RPC, send it to the connected server, and
  1007  	// wait for a response on the returned channel.
  1008  	return ReceiveFuture(c.SendCmd(cmd))
  1009  }
  1010  
  1011  // Disconnected returns whether or not the server is disconnected.  If a
  1012  // websocket client was created but never connected, this also returns false.
  1013  func (c *Client) Disconnected() bool {
  1014  	c.mtx.Lock()
  1015  	defer c.mtx.Unlock()
  1016  
  1017  	select {
  1018  	case <-c.connEstablished:
  1019  		return c.disconnected
  1020  	default:
  1021  		return false
  1022  	}
  1023  }
  1024  
  1025  // doDisconnect disconnects the websocket associated with the client if it
  1026  // hasn't already been disconnected.  It will return false if the disconnect is
  1027  // not needed or the client is running in HTTP POST mode.
  1028  //
  1029  // This function is safe for concurrent access.
  1030  func (c *Client) doDisconnect() bool {
  1031  	if c.config.HTTPPostMode {
  1032  		return false
  1033  	}
  1034  
  1035  	c.mtx.Lock()
  1036  	defer c.mtx.Unlock()
  1037  
  1038  	// Nothing to do if already disconnected.
  1039  	if c.disconnected {
  1040  		return false
  1041  	}
  1042  
  1043  	log.Tracef("Disconnecting RPC client %s", c.config.Host)
  1044  	close(c.disconnect)
  1045  	if c.wsConn != nil {
  1046  		c.wsConn.Close()
  1047  	}
  1048  	c.disconnected = true
  1049  	return true
  1050  }
  1051  
  1052  // doShutdown closes the shutdown channel and logs the shutdown unless shutdown
  1053  // is already in progress.  It will return false if the shutdown is not needed.
  1054  //
  1055  // This function is safe for concurrent access.
  1056  func (c *Client) doShutdown() bool {
  1057  	// Ignore the shutdown request if the client is already in the process
  1058  	// of shutting down or already shutdown.
  1059  	select {
  1060  	case <-c.shutdown:
  1061  		return false
  1062  	default:
  1063  	}
  1064  
  1065  	log.Tracef("Shutting down RPC client %s", c.config.Host)
  1066  	close(c.shutdown)
  1067  	return true
  1068  }
  1069  
  1070  // Disconnect disconnects the current websocket associated with the client.  The
  1071  // connection will automatically be re-established unless the client was
  1072  // created with the DisableAutoReconnect flag.
  1073  //
  1074  // This function has no effect when the client is running in HTTP POST mode.
  1075  func (c *Client) Disconnect() {
  1076  	// Nothing to do if already disconnected or running in HTTP POST mode.
  1077  	if !c.doDisconnect() {
  1078  		return
  1079  	}
  1080  
  1081  	c.requestLock.Lock()
  1082  	defer c.requestLock.Unlock()
  1083  
  1084  	// When operating without auto reconnect, send errors to any pending
  1085  	// requests and shutdown the client.
  1086  	if c.config.DisableAutoReconnect {
  1087  		for e := c.requestList.Front(); e != nil; e = e.Next() {
  1088  			req := e.Value.(*jsonRequest)
  1089  			req.responseChan <- &Response{
  1090  				result: nil,
  1091  				err:    ErrClientDisconnect,
  1092  			}
  1093  		}
  1094  		c.removeAllRequests()
  1095  		c.doShutdown()
  1096  	}
  1097  }
  1098  
  1099  // Shutdown shuts down the client by disconnecting any connections associated
  1100  // with the client and, when automatic reconnect is enabled, preventing future
  1101  // attempts to reconnect.  It also stops all goroutines.
  1102  func (c *Client) Shutdown() {
  1103  	// Do the shutdown under the request lock to prevent clients from
  1104  	// adding new requests while the client shutdown process is initiated.
  1105  	c.requestLock.Lock()
  1106  	defer c.requestLock.Unlock()
  1107  
  1108  	// Ignore the shutdown request if the client is already in the process
  1109  	// of shutting down or already shutdown.
  1110  	if !c.doShutdown() {
  1111  		return
  1112  	}
  1113  
  1114  	// Send the ErrClientShutdown error to any pending requests.
  1115  	for e := c.requestList.Front(); e != nil; e = e.Next() {
  1116  		req := e.Value.(*jsonRequest)
  1117  		req.responseChan <- &Response{
  1118  			result: nil,
  1119  			err:    ErrClientShutdown,
  1120  		}
  1121  	}
  1122  	c.removeAllRequests()
  1123  
  1124  	// Disconnect the client if needed.
  1125  	c.doDisconnect()
  1126  }
  1127  
  1128  // start begins processing input and output messages.
  1129  func (c *Client) start() {
  1130  	log.Tracef("Starting RPC client %s", c.config.Host)
  1131  
  1132  	// Start the I/O processing handlers depending on whether the client is
  1133  	// in HTTP POST mode or the default websocket mode.
  1134  	if c.config.HTTPPostMode {
  1135  		c.wg.Add(1)
  1136  		go c.sendPostHandler()
  1137  	} else {
  1138  		c.wg.Add(3)
  1139  		go func() {
  1140  			if c.ntfnHandlers != nil {
  1141  				if c.ntfnHandlers.OnClientConnected != nil {
  1142  					c.ntfnHandlers.OnClientConnected()
  1143  				}
  1144  			}
  1145  			c.wg.Done()
  1146  		}()
  1147  		go c.wsInHandler()
  1148  		go c.wsOutHandler()
  1149  	}
  1150  }
  1151  
  1152  // WaitForShutdown blocks until the client goroutines are stopped and the
  1153  // connection is closed.
  1154  func (c *Client) WaitForShutdown() {
  1155  	c.wg.Wait()
  1156  }
  1157  
  1158  // ConnConfig describes the connection configuration parameters for the client.
  1159  // This
  1160  type ConnConfig struct {
  1161  	// Host is the IP address and port of the RPC server you want to connect
  1162  	// to.
  1163  	Host string
  1164  
  1165  	// Endpoint is the websocket endpoint on the RPC server.  This is
  1166  	// typically "ws".
  1167  	Endpoint string
  1168  
  1169  	// User is the username to use to authenticate to the RPC server.
  1170  	User string
  1171  
  1172  	// Pass is the passphrase to use to authenticate to the RPC server.
  1173  	Pass string
  1174  
  1175  	// CookiePath is the path to a cookie file containing the username and
  1176  	// passphrase to use to authenticate to the RPC server.  It is used
  1177  	// instead of User and Pass if non-empty.
  1178  	CookiePath string
  1179  
  1180  	cookieLastCheckTime time.Time
  1181  	cookieLastModTime   time.Time
  1182  	cookieLastUser      string
  1183  	cookieLastPass      string
  1184  	cookieLastErr       error
  1185  
  1186  	// Params is the string representing the network that the server
  1187  	// is running. If there is no parameter set in the config, then
  1188  	// mainnet will be used by default.
  1189  	Params string
  1190  
  1191  	// DisableTLS specifies whether transport layer security should be
  1192  	// disabled.  It is recommended to always use TLS if the RPC server
  1193  	// supports it as otherwise your username and password is sent across
  1194  	// the wire in cleartext.
  1195  	DisableTLS bool
  1196  
  1197  	// SkipVerify instruct the client to skip verifying TLS certificate.
  1198  	SkipVerify bool
  1199  
  1200  	// Certificates are the bytes for a PEM-encoded certificate chain used
  1201  	// for the TLS connection.  It has no effect if the DisableTLS parameter
  1202  	// is true.
  1203  	Certificates []byte
  1204  
  1205  	// Proxy specifies to connect through a SOCKS 5 proxy server.  It may
  1206  	// be an empty string if a proxy is not required.
  1207  	Proxy string
  1208  
  1209  	// ProxyUser is an optional username to use for the proxy server if it
  1210  	// requires authentication.  It has no effect if the Proxy parameter
  1211  	// is not set.
  1212  	ProxyUser string
  1213  
  1214  	// ProxyPass is an optional password to use for the proxy server if it
  1215  	// requires authentication.  It has no effect if the Proxy parameter
  1216  	// is not set.
  1217  	ProxyPass string
  1218  
  1219  	// DisableAutoReconnect specifies the client should not automatically
  1220  	// try to reconnect to the server when it has been disconnected.
  1221  	DisableAutoReconnect bool
  1222  
  1223  	// DisableConnectOnNew specifies that a websocket client connection
  1224  	// should not be tried when creating the client with New.  Instead, the
  1225  	// client is created and returned unconnected, and Connect must be
  1226  	// called manually.
  1227  	DisableConnectOnNew bool
  1228  
  1229  	// HTTPPostMode instructs the client to run using multiple independent
  1230  	// connections issuing HTTP POST requests instead of using the default
  1231  	// of websockets.  Websockets are generally preferred as some of the
  1232  	// features of the client such notifications only work with websockets,
  1233  	// however, not all servers support the websocket extensions, so this
  1234  	// flag can be set to true to use basic HTTP POST requests instead.
  1235  	HTTPPostMode bool
  1236  
  1237  	// ExtraHeaders specifies the extra headers when perform request. It's
  1238  	// useful when RPC provider need customized headers.
  1239  	ExtraHeaders map[string]string
  1240  
  1241  	// EnableBCInfoHacks is an option provided to enable compatibility hacks
  1242  	// when connecting to blockchain.info RPC server
  1243  	EnableBCInfoHacks bool
  1244  }
  1245  
  1246  // getAuth returns the username and passphrase that will actually be used for
  1247  // this connection.  This will be the result of checking the cookie if a cookie
  1248  // path is configured; if not, it will be the user-configured username and
  1249  // passphrase.
  1250  func (config *ConnConfig) getAuth() (username, passphrase string, err error) {
  1251  	// Try username+passphrase auth first.
  1252  	if config.Pass != "" {
  1253  		return config.User, config.Pass, nil
  1254  	}
  1255  
  1256  	// If no username or passphrase is set, try cookie auth.
  1257  	return config.retrieveCookie()
  1258  }
  1259  
  1260  // retrieveCookie returns the cookie username and passphrase.
  1261  func (config *ConnConfig) retrieveCookie() (username, passphrase string, err error) {
  1262  	if !config.cookieLastCheckTime.IsZero() && time.Now().Before(config.cookieLastCheckTime.Add(30*time.Second)) {
  1263  		return config.cookieLastUser, config.cookieLastPass, config.cookieLastErr
  1264  	}
  1265  
  1266  	config.cookieLastCheckTime = time.Now()
  1267  
  1268  	st, err := os.Stat(config.CookiePath)
  1269  	if err != nil {
  1270  		config.cookieLastErr = err
  1271  		return config.cookieLastUser, config.cookieLastPass, config.cookieLastErr
  1272  	}
  1273  
  1274  	modTime := st.ModTime()
  1275  	if !modTime.Equal(config.cookieLastModTime) {
  1276  		config.cookieLastModTime = modTime
  1277  		config.cookieLastUser, config.cookieLastPass, config.cookieLastErr = readCookieFile(config.CookiePath)
  1278  	}
  1279  
  1280  	return config.cookieLastUser, config.cookieLastPass, config.cookieLastErr
  1281  }
  1282  
  1283  // newHTTPClient returns a new http client that is configured according to the
  1284  // proxy and TLS settings in the associated connection configuration.
  1285  func newHTTPClient(config *ConnConfig) (*http.Client, error) {
  1286  	// Set proxy function if there is a proxy configured.
  1287  	var proxyFunc func(*http.Request) (*url.URL, error)
  1288  	if config.Proxy != "" {
  1289  		proxyURL, err := url.Parse(config.Proxy)
  1290  		if err != nil {
  1291  			return nil, err
  1292  		}
  1293  		proxyFunc = http.ProxyURL(proxyURL)
  1294  	}
  1295  
  1296  	// Configure TLS if needed.
  1297  	var tlsConfig *tls.Config
  1298  	if !config.DisableTLS {
  1299  		if len(config.Certificates) > 0 {
  1300  			pool := x509.NewCertPool()
  1301  			pool.AppendCertsFromPEM(config.Certificates)
  1302  			tlsConfig = &tls.Config{
  1303  				RootCAs:            pool,
  1304  				InsecureSkipVerify: config.SkipVerify,
  1305  			}
  1306  		}
  1307  	}
  1308  
  1309  	client := http.Client{
  1310  		Transport: &http.Transport{
  1311  			Proxy:           proxyFunc,
  1312  			TLSClientConfig: tlsConfig,
  1313  		},
  1314  	}
  1315  
  1316  	return &client, nil
  1317  }
  1318  
  1319  // dial opens a websocket connection using the passed connection configuration
  1320  // details.
  1321  func dial(config *ConnConfig) (*websocket.Conn, error) {
  1322  	// Setup TLS if not disabled.
  1323  	var tlsConfig *tls.Config
  1324  	var scheme = "ws"
  1325  	if !config.DisableTLS {
  1326  		tlsConfig = &tls.Config{
  1327  			MinVersion:         tls.VersionTLS12,
  1328  			InsecureSkipVerify: config.SkipVerify,
  1329  		}
  1330  		if len(config.Certificates) > 0 {
  1331  			pool := x509.NewCertPool()
  1332  			pool.AppendCertsFromPEM(config.Certificates)
  1333  			tlsConfig.RootCAs = pool
  1334  		}
  1335  		scheme = "wss"
  1336  	}
  1337  
  1338  	// Create a websocket dialer that will be used to make the connection.
  1339  	// It is modified by the proxy setting below as needed.
  1340  	dialer := websocket.Dialer{TLSClientConfig: tlsConfig}
  1341  
  1342  	// Setup the proxy if one is configured.
  1343  	if config.Proxy != "" {
  1344  		proxy := &socks.Proxy{
  1345  			Addr:     config.Proxy,
  1346  			Username: config.ProxyUser,
  1347  			Password: config.ProxyPass,
  1348  		}
  1349  		dialer.NetDial = proxy.Dial
  1350  	}
  1351  
  1352  	// The RPC server requires basic authorization, so create a custom
  1353  	// request header with the Authorization header set.
  1354  	user, pass, err := config.getAuth()
  1355  	if err != nil {
  1356  		return nil, err
  1357  	}
  1358  	login := user + ":" + pass
  1359  	auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
  1360  	requestHeader := make(http.Header)
  1361  	requestHeader.Add("Authorization", auth)
  1362  	for key, value := range config.ExtraHeaders {
  1363  		requestHeader.Add(key, value)
  1364  	}
  1365  
  1366  	// Dial the connection.
  1367  	url := fmt.Sprintf("%s://%s/%s", scheme, config.Host, config.Endpoint)
  1368  	wsConn, resp, err := dialer.Dial(url, requestHeader)
  1369  	if err != nil {
  1370  		if err != websocket.ErrBadHandshake || resp == nil {
  1371  			return nil, err
  1372  		}
  1373  
  1374  		// Detect HTTP authentication error status codes.
  1375  		if resp.StatusCode == http.StatusUnauthorized ||
  1376  			resp.StatusCode == http.StatusForbidden {
  1377  			return nil, ErrInvalidAuth
  1378  		}
  1379  
  1380  		// The connection was authenticated and the status response was
  1381  		// ok, but the websocket handshake still failed, so the endpoint
  1382  		// is invalid in some way.
  1383  		if resp.StatusCode == http.StatusOK {
  1384  			return nil, ErrInvalidEndpoint
  1385  		}
  1386  
  1387  		// Return the status text from the server if none of the special
  1388  		// cases above apply.
  1389  		return nil, errors.New(resp.Status)
  1390  	}
  1391  	resp.Body.Close()
  1392  	return wsConn, nil
  1393  }
  1394  
  1395  // New creates a new RPC client based on the provided connection configuration
  1396  // details.  The notification handlers parameter may be nil if you are not
  1397  // interested in receiving notifications and will be ignored if the
  1398  // configuration is set to run in HTTP POST mode.
  1399  func New(config *ConnConfig, ntfnHandlers *NotificationHandlers) (*Client, error) {
  1400  	// Either open a websocket connection or create an HTTP client depending
  1401  	// on the HTTP POST mode.  Also, set the notification handlers to nil
  1402  	// when running in HTTP POST mode.
  1403  	var wsConn *websocket.Conn
  1404  	var httpClient *http.Client
  1405  	connEstablished := make(chan struct{})
  1406  	var start bool
  1407  	if config.HTTPPostMode {
  1408  		ntfnHandlers = nil
  1409  		start = true
  1410  
  1411  		var err error
  1412  		httpClient, err = newHTTPClient(config)
  1413  		if err != nil {
  1414  			return nil, err
  1415  		}
  1416  	} else {
  1417  		if !config.DisableConnectOnNew {
  1418  			var err error
  1419  			wsConn, err = dial(config)
  1420  			if err != nil {
  1421  				return nil, err
  1422  			}
  1423  			start = true
  1424  		}
  1425  	}
  1426  
  1427  	client := &Client{
  1428  		config:          config,
  1429  		wsConn:          wsConn,
  1430  		httpClient:      httpClient,
  1431  		requestMap:      make(map[uint64]*list.Element),
  1432  		requestList:     list.New(),
  1433  		batch:           false,
  1434  		batchList:       list.New(),
  1435  		ntfnHandlers:    ntfnHandlers,
  1436  		ntfnState:       newNotificationState(),
  1437  		sendChan:        make(chan []byte, sendBufferSize),
  1438  		sendPostChan:    make(chan *jsonRequest, sendPostBufferSize),
  1439  		connEstablished: connEstablished,
  1440  		disconnect:      make(chan struct{}),
  1441  		shutdown:        make(chan struct{}),
  1442  	}
  1443  
  1444  	// Default network is mainnet, no parameters are necessary but if mainnet
  1445  	// is specified it will be the param
  1446  	switch config.Params {
  1447  	case "":
  1448  		fallthrough
  1449  	case chaincfg.MainNetParams.Name:
  1450  		client.chainParams = &chaincfg.MainNetParams
  1451  	case chaincfg.TestNet3Params.Name:
  1452  		client.chainParams = &chaincfg.TestNet3Params
  1453  	case chaincfg.RegressionNetParams.Name:
  1454  		client.chainParams = &chaincfg.RegressionNetParams
  1455  	case chaincfg.SimNetParams.Name:
  1456  		client.chainParams = &chaincfg.SimNetParams
  1457  	default:
  1458  		return nil, fmt.Errorf("rpcclient.New: Unknown chain %s", config.Params)
  1459  	}
  1460  
  1461  	if start {
  1462  		log.Infof("Established connection to RPC server %s",
  1463  			config.Host)
  1464  		close(connEstablished)
  1465  		client.start()
  1466  		if !client.config.HTTPPostMode && !client.config.DisableAutoReconnect {
  1467  			client.wg.Add(1)
  1468  			go client.wsReconnectHandler()
  1469  		}
  1470  	}
  1471  
  1472  	return client, nil
  1473  }
  1474  
  1475  // Batch is a factory that creates a client able to interact with the server using
  1476  // JSON-RPC 2.0. The client is capable of accepting an arbitrary number of requests
  1477  // and having the server process the all at the same time. It's compatible with both
  1478  // btcd and bitcoind
  1479  func NewBatch(config *ConnConfig) (*Client, error) {
  1480  	if !config.HTTPPostMode {
  1481  		return nil, errors.New("http post mode is required to use batch client")
  1482  	}
  1483  	// notification parameter is nil since notifications are not supported in POST mode.
  1484  	client, err := New(config, nil)
  1485  	if err != nil {
  1486  		return nil, err
  1487  	}
  1488  	client.batch = true //copy the client with changed batch setting
  1489  	client.start()
  1490  	return client, nil
  1491  }
  1492  
  1493  // Connect establishes the initial websocket connection.  This is necessary when
  1494  // a client was created after setting the DisableConnectOnNew field of the
  1495  // Config struct.
  1496  //
  1497  // Up to tries number of connections (each after an increasing backoff) will
  1498  // be tried if the connection can not be established.  The special value of 0
  1499  // indicates an unlimited number of connection attempts.
  1500  //
  1501  // This method will error if the client is not configured for websockets, if the
  1502  // connection has already been established, or if none of the connection
  1503  // attempts were successful.
  1504  func (c *Client) Connect(tries int) error {
  1505  	c.mtx.Lock()
  1506  	defer c.mtx.Unlock()
  1507  
  1508  	if c.config.HTTPPostMode {
  1509  		return ErrNotWebsocketClient
  1510  	}
  1511  	if c.wsConn != nil {
  1512  		return ErrClientAlreadyConnected
  1513  	}
  1514  
  1515  	// Begin connection attempts.  Increase the backoff after each failed
  1516  	// attempt, up to a maximum of one minute.
  1517  	var err error
  1518  	var backoff time.Duration
  1519  	for i := 0; tries == 0 || i < tries; i++ {
  1520  		var wsConn *websocket.Conn
  1521  		wsConn, err = dial(c.config)
  1522  		if err != nil {
  1523  			backoff = connectionRetryInterval * time.Duration(i+1)
  1524  			if backoff > time.Minute {
  1525  				backoff = time.Minute
  1526  			}
  1527  			time.Sleep(backoff)
  1528  			continue
  1529  		}
  1530  
  1531  		// Connection was established.  Set the websocket connection
  1532  		// member of the client and start the goroutines necessary
  1533  		// to run the client.
  1534  		log.Infof("Established connection to RPC server %s",
  1535  			c.config.Host)
  1536  		c.wsConn = wsConn
  1537  		close(c.connEstablished)
  1538  		c.start()
  1539  		if !c.config.DisableAutoReconnect {
  1540  			c.wg.Add(1)
  1541  			go c.wsReconnectHandler()
  1542  		}
  1543  		return nil
  1544  	}
  1545  
  1546  	// All connection attempts failed, so return the last error.
  1547  	return err
  1548  }
  1549  
  1550  const (
  1551  	// bitcoind19Str is the string representation of bitcoind v0.19.0.
  1552  	bitcoind19Str = "0.19.0"
  1553  
  1554  	// bitcoindVersionPrefix specifies the prefix included in every bitcoind
  1555  	// version exposed through GetNetworkInfo.
  1556  	bitcoindVersionPrefix = "/Satoshi:"
  1557  
  1558  	// bitcoindVersionSuffix specifies the suffix included in every bitcoind
  1559  	// version exposed through GetNetworkInfo.
  1560  	bitcoindVersionSuffix = "/"
  1561  )
  1562  
  1563  // parseBitcoindVersion parses the bitcoind version from its string
  1564  // representation.
  1565  func parseBitcoindVersion(version string) BackendVersion {
  1566  	// Trim the version of its prefix and suffix to determine the
  1567  	// appropriate version number.
  1568  	version = strings.TrimPrefix(
  1569  		strings.TrimSuffix(version, bitcoindVersionSuffix),
  1570  		bitcoindVersionPrefix,
  1571  	)
  1572  	switch {
  1573  	case version < bitcoind19Str:
  1574  		return BitcoindPre19
  1575  	default:
  1576  		return BitcoindPost19
  1577  	}
  1578  }
  1579  
  1580  // BackendVersion retrieves the version of the backend the client is currently
  1581  // connected to.
  1582  func (c *Client) BackendVersion() (BackendVersion, error) {
  1583  	c.backendVersionMu.Lock()
  1584  	defer c.backendVersionMu.Unlock()
  1585  
  1586  	if c.backendVersion != nil {
  1587  		return *c.backendVersion, nil
  1588  	}
  1589  
  1590  	// We'll start by calling GetInfo. This method doesn't exist for
  1591  	// bitcoind nodes as of v0.16.0, so we'll assume the client is connected
  1592  	// to a btcd backend if it does exist.
  1593  	info, err := c.GetInfo()
  1594  
  1595  	switch err := err.(type) {
  1596  	// Parse the btcd version and cache it.
  1597  	case nil:
  1598  		log.Debugf("Detected lbcd version: %v", info.Version)
  1599  		version := Lbcd
  1600  		c.backendVersion = &version
  1601  		return *c.backendVersion, nil
  1602  
  1603  	// Inspect the RPC error to ensure the method was not found, otherwise
  1604  	// we actually ran into an error.
  1605  	case *btcjson.RPCError:
  1606  		if err.Code != btcjson.ErrRPCMethodNotFound.Code {
  1607  			return 0, fmt.Errorf("unable to detect lbcd version: "+
  1608  				"%v", err)
  1609  		}
  1610  
  1611  	default:
  1612  		return 0, fmt.Errorf("unable to detect lbcd version: %v", err)
  1613  	}
  1614  
  1615  	// Since the GetInfo method was not found, we assume the client is
  1616  	// connected to a bitcoind backend, which exposes its version through
  1617  	// GetNetworkInfo.
  1618  	networkInfo, err := c.GetNetworkInfo()
  1619  	if err != nil {
  1620  		return 0, fmt.Errorf("unable to detect bitcoind version: %v", err)
  1621  	}
  1622  
  1623  	// Parse the bitcoind version and cache it.
  1624  	log.Debugf("Detected bitcoind version: %v", networkInfo.SubVersion)
  1625  	version := parseBitcoindVersion(networkInfo.SubVersion)
  1626  	c.backendVersion = &version
  1627  
  1628  	return *c.backendVersion, nil
  1629  }
  1630  
  1631  func (c *Client) sendAsync() FutureGetBulkResult {
  1632  	// convert the array of marshalled json requests to a single request we can send
  1633  	responseChan := make(chan *Response, 1)
  1634  	marshalledRequest := []byte("[")
  1635  	for iter := c.batchList.Front(); iter != nil; iter = iter.Next() {
  1636  		request := iter.Value.(*jsonRequest)
  1637  		marshalledRequest = append(marshalledRequest, request.marshalledJSON...)
  1638  		marshalledRequest = append(marshalledRequest, []byte(",")...)
  1639  	}
  1640  	if len(marshalledRequest) > 0 {
  1641  		// removes the trailing comma to process the request individually
  1642  		marshalledRequest = marshalledRequest[:len(marshalledRequest)-1]
  1643  	}
  1644  	marshalledRequest = append(marshalledRequest, []byte("]")...)
  1645  	request := jsonRequest{
  1646  		id:             c.NextID(),
  1647  		method:         "",
  1648  		cmd:            nil,
  1649  		marshalledJSON: marshalledRequest,
  1650  		responseChan:   responseChan,
  1651  	}
  1652  	c.sendPostRequest(&request)
  1653  	return responseChan
  1654  }
  1655  
  1656  // Marshall's bulk requests and sends to the server
  1657  // creates a response channel to receive the response
  1658  func (c *Client) Send() error {
  1659  	// if batchlist is empty, there's nothing to send
  1660  	if c.batchList.Len() == 0 {
  1661  		return nil
  1662  	}
  1663  
  1664  	// clear batchlist in case of an error
  1665  	defer func() {
  1666  		c.batchList = list.New()
  1667  	}()
  1668  
  1669  	result, err := c.sendAsync().Receive()
  1670  
  1671  	if err != nil {
  1672  		return err
  1673  	}
  1674  
  1675  	for iter := c.batchList.Front(); iter != nil; iter = iter.Next() {
  1676  		var requestError error
  1677  		request := iter.Value.(*jsonRequest)
  1678  		individualResult := result[request.id]
  1679  		fullResult, err := json.Marshal(individualResult.Result)
  1680  		if err != nil {
  1681  			return err
  1682  		}
  1683  
  1684  		if individualResult.Error != nil {
  1685  			requestError = individualResult.Error
  1686  		}
  1687  
  1688  		result := Response{
  1689  			result: fullResult,
  1690  			err:    requestError,
  1691  		}
  1692  		request.responseChan <- &result
  1693  	}
  1694  	return nil
  1695  }