func (c *Client) SendRequest(node string, remoteCall RPCFunction,
	args map[RequestArgument]interface{}) (interface{}, error) {
	var err error
	handleError := func(err error) error {
		if _, ok := err.(net.Error); ok {
			return &Error{ErrNodeComm, err.Error(), false}
		}
		if err != nil && !strings.HasPrefix(err.Error(), "RufsError: ") {
			err = &Error{ErrRemoteAction, err.Error(), err.Error() == os.ErrNotExist.Error()}
		}
		return err
	}
	c.maplock.Lock()
	laddr, ok := c.peers[node]
	c.maplock.Unlock()
	if ok {
		c.maplock.Lock()
		conn, ok := c.conns[node]
		c.maplock.Unlock()
		if !ok {
			nconn, err := net.DialTimeout("tcp", laddr, DialTimeout)
			if err != nil {
				LogDebug(c.token.NodeName, ": ",
					fmt.Sprintf("- %v.%v (laddr=%v err=%v)",
						node, remoteCall, laddr, err))
				return nil, handleError(err)
			}
			if c.cert != nil && c.cert.Certificate[0] != nil {
				config := tls.Config{
					Certificates:       []tls.Certificate{*c.cert},
					InsecureSkipVerify: true,
				}
				tlsconn := tls.Client(nconn, &config)
				tlsconn.Handshake()
				rfp := fingerprint(tlsconn.ConnectionState().PeerCertificates[0].Raw)
				c.maplock.Lock()
				expected, _ := c.fingerprints[node]
				c.maplock.Unlock()
				if expected == "" {
					c.maplock.Lock()
					c.fingerprints[node] = rfp
					c.maplock.Unlock()
				} else if expected != rfp {
					LogDebug(c.token.NodeName, ": ",
						fmt.Sprintf("Not trusting %v (laddr=%v) presented fingerprint: %v expected fingerprint: %v", node, laddr, rfp, expected))
					return nil, &Error{ErrUntrustedTarget, node, false}
				}
				LogDebug(c.token.NodeName, ": ",
					fmt.Sprintf("%v (laddr=%v) has SSL fingerprint %v ", node, laddr, rfp))
				nconn = tlsconn
			}
			conn = rpc.NewClient(nconn)
			c.maplock.Lock()
			c.conns[node] = conn
			c.maplock.Unlock()
		}
		request := map[RequestArgument]interface{}{
			RequestTARGET: node,
			RequestTOKEN:  c.token,
		}
		if args != nil {
			for k, v := range args {
				request[k] = v
			}
		}
		var response interface{}
		LogDebug(c.token.NodeName, ": ",
			fmt.Sprintf("> %v.%v (laddr=%v)", node, remoteCall, laddr))
		err = conn.Call("RufsServer."+string(remoteCall), request, &response)
		if !c.redial && (err == rpc.ErrShutdown || err == io.EOF || err == io.ErrUnexpectedEOF) {
			c.maplock.Lock()
			delete(c.conns, node)
			c.redial = true  
			c.maplock.Unlock()
			return c.SendRequest(node, remoteCall, args)
		}
		c.maplock.Lock()
		c.redial = false
		c.maplock.Unlock()
		LogDebug(c.token.NodeName, ": ",
			fmt.Sprintf("< %v.%v (err=%v)", node, remoteCall, err))
		return response, handleError(err)
	}
	return nil, &Error{ErrUnknownTarget, node, false}
}
/*
SendRequest sends a request to another node.
package node
import (
	"crypto/tls"
	"encoding/gob"
	"fmt"
	"io"
	"net"
	"net/rpc"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)
func init() {
	gob.Register(&RufsNodeToken{})
	gob.Register(map[string]string{})
}
var DialTimeout = 10 * time.Second
type RufsNodeToken struct {
	NodeName string
	NodeAuth string
}
type Client struct {
	token        *RufsNodeToken          
	rpc          string                  
	peers        map[string]string       
	conns        map[string]*rpc.Client  
	fingerprints map[string]string       
	cert         *tls.Certificate        
	maplock      *sync.RWMutex           
	redial       bool                    
}
func (c *Client) SSLFingerprint() string {
	var ret string
	if c.cert != nil && c.cert.Certificate[0] != nil {
		ret = fingerprint(c.cert.Certificate[0])
	}
	return ret
}
func (c *Client) Shutdown() {
	c.maplock.Lock()
	defer c.maplock.Unlock()
	for _, c := range c.conns {
		c.Close()
	}
	c.conns = make(map[string]*rpc.Client)
}
func (c *Client) RegisterPeer(node string, rpc string, fingerprint string) error {
	if _, ok := c.peers[node]; ok {
		return fmt.Errorf("Peer already registered: %v", node)
	} else if rpc == "" {
		return fmt.Errorf("RPC interface must not be empty")
	}
	c.maplock.Lock()
	c.peers[node] = rpc
	delete(c.conns, node)
	c.fingerprints[node] = fingerprint
	c.maplock.Unlock()
	return nil
}
func (c *Client) Peers() ([]string, []string) {
	ret := make([]string, 0, len(c.peers))
	fps := make([]string, len(c.peers))
	c.maplock.Lock()
	defer c.maplock.Unlock()
	for k := range c.peers {
		ret = append(ret, k)
	}
	sort.Strings(ret)
	for i, node := range ret {
		fps[i] = c.fingerprints[node]
	}
	return ret, fps
}
func (c *Client) RemovePeer(node string) {
	c.maplock.Lock()
	delete(c.peers, node)
	delete(c.conns, node)
	delete(c.fingerprints, node)
	c.maplock.Unlock()
}
func (c *Client) SendPing(node string, rpc string) ([]string, string, error) {
	var ret []string
	var fp string
	if _, ok := c.peers[node]; !ok && rpc != "" {
		c.maplock.Lock()
		c.peers[node] = rpc
		c.maplock.Unlock()
		defer func() {
			c.maplock.Lock()
			delete(c.peers, node)
			delete(c.conns, node)
			delete(c.fingerprints, node)
			c.maplock.Unlock()
		}()
	}
	res, err := c.SendRequest(node, RPCPing, nil)
	if res != nil && err == nil {
		ret = res.([]string)
		c.maplock.Lock()
		fp = c.fingerprints[node]
		c.maplock.Unlock()
	}
	return ret, fp, err
}
func (c *Client) SendData(node string, ctrl map[string]string, data []byte) ([]byte, error) {
	if _, ok := c.peers[node]; !ok {
		return nil, fmt.Errorf("Unknown peer: %v", node)
	}
	res, err := c.SendRequest(node, RPCData, map[RequestArgument]interface{}{
		RequestCTRL: ctrl,
		RequestDATA: data,
	})
	if res != nil {
		return res.([]byte), err
	}
	return nil, err
}