Example #1
0
// respondToAnyCmd checks that a parsed command is a standard or
// extension JSON-RPC command and runs the proper handler to reply to
// the command.  Any and all responses are sent to the wallet from
// this function.
func respondToAnyCmd(cmd btcjson.Cmd, s *rpcServer, wallet walletChan) {
	// Lookup the websocket extension for the command and if it doesn't
	// exist fallback to handling the command as a standard command.
	wsHandler, ok := wsHandlers[cmd.Method()]
	if !ok {
		reply := standardCmdReply(cmd, s)
		mreply, _ := json.Marshal(reply)
		wallet <- mreply
		return
	}

	// Call the appropriate handler which responds unless there was an
	// error in which case the error is marshalled and sent here.
	if err := wsHandler(s, cmd, wallet); err != nil {
		var reply btcjson.Reply
		jsonErr, ok := err.(btcjson.Error)
		if ok {
			reply.Error = &jsonErr
			mreply, _ := json.Marshal(reply)
			wallet <- mreply
			return
		}

		// In the case where we did not have a btcjson
		// error to begin with, make a new one to send,
		// but this really should not happen.
		jsonErr = btcjson.Error{
			Code:    btcjson.ErrInternal.Code,
			Message: err.Error(),
		}
		reply.Error = &jsonErr
		mreply, _ := json.Marshal(reply)
		wallet <- mreply
	}
}
Example #2
0
// jsonRPCRead is the RPC wrapper around the jsonRead function to handle reading
// and responding to RPC messages.
func jsonRPCRead(w http.ResponseWriter, r *http.Request, s *rpcServer) {
	if atomic.LoadInt32(&s.shutdown) != 0 {
		return
	}
	body, err := btcjson.GetRaw(r.Body)
	if err != nil {
		rpcsLog.Errorf("Error getting json message: %v", err)
		return
	}

	var reply btcjson.Reply
	cmd, jsonErr := parseCmd(body)
	if cmd != nil {
		// Unmarshaling at least a valid JSON-RPC message succeeded.
		// Use the provided id for errors.
		id := cmd.Id()
		reply.Id = &id
	}
	if jsonErr != nil {
		reply.Error = jsonErr
	} else {
		reply = standardCmdReply(cmd, s)
	}

	rpcsLog.Tracef("reply: %v", reply)

	msg, err := btcjson.MarshallAndSend(reply, w)
	if err != nil {
		rpcsLog.Errorf(msg)
		return
	}
	rpcsLog.Debugf(msg)
}
Example #3
0
// websocketJSONHandler parses and handles a marshalled json message,
// sending the marshalled reply to a wallet notification channel.
func (s *rpcServer) websocketJSONHandler(wallet walletChan, msg []byte) {
	s.wg.Add(1)
	defer s.wg.Done()

	cmd, jsonErr := parseCmd(msg)
	if jsonErr != nil {
		var reply btcjson.Reply
		if cmd != nil {
			// Unmarshaling at least a valid JSON-RPC message succeeded.
			// Use the provided id for errors.
			id := cmd.Id()
			reply.Id = &id
		}
		reply.Error = jsonErr
		mreply, _ := json.Marshal(reply)
		wallet <- mreply
		return
	}

	respondToAnyCmd(cmd, s, wallet)
}
Example #4
0
// websocketJSONHandler parses and handles a marshalled json message,
// sending the marshalled reply to a wallet notification channel.
func (s *rpcServer) websocketJSONHandler(r chan *btcjson.Reply, c handlerChans, msg string) error {
	var resp *btcjson.Reply

	cmd, jsonErr := parseCmd([]byte(msg))
	if jsonErr != nil {
		resp = &btcjson.Reply{}
		if cmd != nil {
			// Unmarshaling at least a valid JSON-RPC message succeeded.
			// Use the provided id for errors.  Requests with no IDs
			// should be ignored.
			id := cmd.Id()
			if id == nil {
				return nil
			}
			resp.Id = &id
		}
		resp.Error = jsonErr
	} else {
		// The first command must be the "authenticate" command if the
		// connection is not already authenticated.
		s.ws.Lock()
		rc := s.ws.connections[c.n]
		if _, ok := cmd.(*btcws.AuthenticateCmd); ok {
			// Validate the provided credentials.
			err := websocketAuthenticate(cmd, rc, s.authsha[:])
			if err != nil {
				s.ws.Unlock()
				return err
			}

			// Generate an empty response to send for the successful
			// authentication.
			id := cmd.Id()
			resp = &btcjson.Reply{
				Id:     &id,
				Result: nil,
				Error:  nil,
			}
		} else if !rc.authenticated {
			rpcsLog.Warnf("Unauthenticated websocket message " +
				"received")
			s.ws.Unlock()
			return ErrBadAuth
		}

		s.ws.Unlock()
	}

	// Find and run handler in new goroutine.
	go func() {
		if resp == nil {
			resp = respondToAnyCmd(cmd, s, c)
		}
		select {
		case <-c.disconnected:
			return

		default:
			r <- resp
		}
	}()

	return nil
}