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