github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/rpc/server.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package rpc
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"reflect"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/juju/loggo"
    14  
    15  	"github.com/juju/juju/rpc/rpcreflect"
    16  )
    17  
    18  const CodeNotImplemented = "not implemented"
    19  
    20  var logger = loggo.GetLogger("juju.rpc")
    21  
    22  // A Codec implements reading and writing of messages in an RPC
    23  // session.  The RPC code calls WriteMessage to write a message to the
    24  // connection and calls ReadHeader and ReadBody in pairs to read
    25  // messages.
    26  type Codec interface {
    27  	// ReadHeader reads a message header into hdr.
    28  	ReadHeader(hdr *Header) error
    29  
    30  	// ReadBody reads a message body into the given body value.  The
    31  	// isRequest parameter specifies whether the message being read
    32  	// is a request; if not, it's a response.  The body value will
    33  	// be a non-nil struct pointer, or nil to signify that the body
    34  	// should be read and discarded.
    35  	ReadBody(body interface{}, isRequest bool) error
    36  
    37  	// WriteMessage writes a message with the given header and body.
    38  	// The body will always be a struct. It may be called concurrently
    39  	// with ReadHeader and ReadBody, but will not be called
    40  	// concurrently with itself.
    41  	WriteMessage(hdr *Header, body interface{}) error
    42  
    43  	// Close closes the codec. It may be called concurrently
    44  	// and should cause the Read methods to unblock.
    45  	Close() error
    46  }
    47  
    48  // Header is a header written before every RPC call.  Since RPC requests
    49  // can be initiated from either side, the header may represent a request
    50  // from the other side or a response to an outstanding request.
    51  type Header struct {
    52  	// RequestId holds the sequence number of the request.
    53  	// For replies, it holds the sequence number of the request
    54  	// that is being replied to.
    55  	RequestId uint64
    56  
    57  	// Request holds the action to invoke.
    58  	Request Request
    59  
    60  	// Error holds the error, if any.
    61  	Error string
    62  
    63  	// ErrorCode holds the code of the error, if any.
    64  	ErrorCode string
    65  }
    66  
    67  // Request represents an RPC to be performed, absent its parameters.
    68  type Request struct {
    69  	// Type holds the type of object to act on.
    70  	Type string
    71  
    72  	// Version holds the version of Type we will be acting on
    73  	Version int
    74  
    75  	// Id holds the id of the object to act on.
    76  	Id string
    77  
    78  	// Action holds the action to perform on the object.
    79  	Action string
    80  }
    81  
    82  // IsRequest returns whether the header represents an RPC request.  If
    83  // it is not a request, it is a response.
    84  func (hdr *Header) IsRequest() bool {
    85  	return hdr.Request.Type != "" || hdr.Request.Action != ""
    86  }
    87  
    88  // Note that we use "client request" and "server request" to name
    89  // requests initiated locally and remotely respectively.
    90  
    91  // Conn represents an RPC endpoint.  It can both initiate and receive
    92  // RPC requests.  There may be multiple outstanding Calls associated
    93  // with a single Client, and a Client may be used by multiple goroutines
    94  // simultaneously.
    95  type Conn struct {
    96  	// codec holds the underlying RPC connection.
    97  	codec Codec
    98  
    99  	// notifier is informed about RPC requests. It may be nil.
   100  	notifier RequestNotifier
   101  
   102  	// srvPending represents the current server requests.
   103  	srvPending sync.WaitGroup
   104  
   105  	// sending guards the write side of the codec - it ensures
   106  	// that codec.WriteMessage is not called concurrently.
   107  	// It also guards shutdown.
   108  	sending sync.Mutex
   109  
   110  	// mutex guards the following values.
   111  	mutex sync.Mutex
   112  
   113  	// methodFinder is used to lookup methods to serve RPC requests. May be
   114  	// nil if nothing is being served.
   115  	methodFinder MethodFinder
   116  
   117  	// root is the current object that we are serving.
   118  	// If it implements the Killer interface, Kill will be called on it
   119  	// as the connection shuts down.
   120  	// If it implements the Cleaner interface, Cleanup will be called on
   121  	// it after the connection has shut down.
   122  	root interface{}
   123  
   124  	// transformErrors is used to transform returned errors.
   125  	transformErrors func(error) error
   126  
   127  	// reqId holds the latest client request id.
   128  	reqId uint64
   129  
   130  	// clientPending holds all pending client requests.
   131  	clientPending map[uint64]*Call
   132  
   133  	// closing is set when the connection is shutting down via
   134  	// Close.  When this is set, no more client or server requests
   135  	// will be initiated.
   136  	closing bool
   137  
   138  	// shutdown is set when the input loop terminates. When this
   139  	// is set, no more client requests will be sent to the server.
   140  	shutdown bool
   141  
   142  	// dead is closed when the input loop terminates.
   143  	dead chan struct{}
   144  
   145  	// inputLoopError holds the error that caused the input loop to
   146  	// terminate prematurely.  It is set before dead is closed.
   147  	inputLoopError error
   148  }
   149  
   150  // RequestNotifier can be implemented to find out about requests
   151  // occurring in an RPC conn, for example to print requests for logging
   152  // purposes. The calls should not block or interact with the Conn object
   153  // as that can cause delays to the RPC server or deadlock.
   154  // Note that the methods on RequestNotifier may
   155  // be called concurrently.
   156  type RequestNotifier interface {
   157  	// ServerRequest informs the RequestNotifier of a request made
   158  	// to the Conn. If the request was not recognized or there was
   159  	// an error reading the body, body will be nil.
   160  	//
   161  	// ServerRequest is called just before the server method
   162  	// is invoked.
   163  	ServerRequest(hdr *Header, body interface{})
   164  
   165  	// ServerReply informs the RequestNotifier of a reply sent to a
   166  	// server request. The given Request gives details of the call
   167  	// that was made; the given Header and body are the header and
   168  	// body sent as reply.
   169  	//
   170  	// ServerReply is called just before the reply is written.
   171  	ServerReply(req Request, hdr *Header, body interface{}, timeSpent time.Duration)
   172  
   173  	// ClientRequest informs the RequestNotifier of a request
   174  	// made from the Conn. It is called just before the request is
   175  	// written.
   176  	ClientRequest(hdr *Header, body interface{})
   177  
   178  	// ClientReply informs the RequestNotifier of a reply received
   179  	// to a request. If the reply was to an unrecognised request,
   180  	// the Request will be zero-valued. If the reply contained an
   181  	// error, body will be nil; otherwise body will be the value that
   182  	// was passed to the Conn.Call method.
   183  	//
   184  	// ClientReply is called just before the reply is handed to
   185  	// back to the caller.
   186  	ClientReply(req Request, hdr *Header, body interface{})
   187  }
   188  
   189  // NewConn creates a new connection that uses the given codec for
   190  // transport, but it does not start it. Conn.Start must be called before
   191  // any requests are sent or received. If notifier is non-nil, the
   192  // appropriate method will be called for every RPC request.
   193  func NewConn(codec Codec, notifier RequestNotifier) *Conn {
   194  	return &Conn{
   195  		codec:         codec,
   196  		clientPending: make(map[uint64]*Call),
   197  		notifier:      notifier,
   198  	}
   199  }
   200  
   201  // Start starts the RPC connection running.  It must be called at least
   202  // once for any RPC connection (client or server side) It has no effect
   203  // if it has already been called.  By default, a connection serves no
   204  // methods.  See Conn.Serve for a description of how to serve methods on
   205  // a Conn.
   206  func (conn *Conn) Start() {
   207  	conn.mutex.Lock()
   208  	defer conn.mutex.Unlock()
   209  	if conn.dead == nil {
   210  		conn.dead = make(chan struct{})
   211  		go conn.input()
   212  	}
   213  }
   214  
   215  // Serve serves RPC requests on the connection by invoking methods on
   216  // root. Note that it does not start the connection running,
   217  // though it may be called once the connection is already started.
   218  //
   219  // The server executes each client request by calling a method on root
   220  // to obtain an object to act on; then it invokes an method on that
   221  // object with the request parameters, possibly returning some result.
   222  //
   223  // Methods on the root value are of the form:
   224  //
   225  //      M(id string) (O, error)
   226  //
   227  // where M is an exported name, conventionally naming the object type,
   228  // id is some identifier for the object and O is the type of the
   229  // returned object.
   230  //
   231  // Methods defined on O may defined in one of the following forms, where
   232  // T and R must be struct types.
   233  //
   234  //	Method()
   235  //	Method() R
   236  //	Method() (R, error)
   237  //	Method() error
   238  //	Method(T)
   239  //	Method(T) R
   240  //	Method(T) (R, error)
   241  //	Method(T) error
   242  //
   243  // If transformErrors is non-nil, it will be called on all returned
   244  // non-nil errors, for example to transform the errors into ServerErrors
   245  // with specified codes.  There will be a panic if transformErrors
   246  // returns nil.
   247  //
   248  // Serve may be called at any time on a connection to change the
   249  // set of methods being served by the connection. This will have
   250  // no effect on calls that are currently being services.
   251  // If root is nil, the connection will serve no methods.
   252  func (conn *Conn) Serve(root interface{}, transformErrors func(error) error) {
   253  	rootValue := rpcreflect.ValueOf(reflect.ValueOf(root))
   254  	if rootValue.IsValid() {
   255  		conn.serve(rootValue, root, transformErrors)
   256  	} else {
   257  		conn.serve(nil, nil, transformErrors)
   258  	}
   259  }
   260  
   261  // ServeFinder serves RPC requests on the connection by invoking methods retrieved
   262  // from root. Note that it does not start the connection running, though
   263  // it may be called once the connection is already started.
   264  //
   265  // The server executes each client request by calling FindMethod to obtain a
   266  // method to invoke. It invokes that method with the request parameters,
   267  // possibly returning some result.
   268  //
   269  // root can optionally implement the Killer method. If implemented, when the
   270  // connection is closed, root.Kill() will be called.
   271  func (conn *Conn) ServeFinder(finder MethodFinder, transformErrors func(error) error) {
   272  	conn.serve(finder, finder, transformErrors)
   273  }
   274  
   275  func (conn *Conn) serve(methodFinder MethodFinder, root interface{}, transformErrors func(error) error) {
   276  	if transformErrors == nil {
   277  		transformErrors = noopTransform
   278  	}
   279  	conn.mutex.Lock()
   280  	defer conn.mutex.Unlock()
   281  	conn.methodFinder = methodFinder
   282  	conn.root = root
   283  	conn.transformErrors = transformErrors
   284  }
   285  
   286  // noopTransform is used when transformErrors is not supplied to Serve.
   287  func noopTransform(err error) error {
   288  	return err
   289  }
   290  
   291  // Dead returns a channel that is closed when the connection
   292  // has been closed or the underlying transport has received
   293  // an error. There may still be outstanding requests.
   294  // Dead must be called after conn.Start has been called.
   295  func (conn *Conn) Dead() <-chan struct{} {
   296  	return conn.dead
   297  }
   298  
   299  // Close closes the connection and its underlying codec; it returns when
   300  // all requests have been terminated.
   301  //
   302  // If the connection is serving requests, and the root value implements
   303  // the Killer interface, its Kill method will be called.  The codec will
   304  // then be closed only when all its outstanding server calls have
   305  // completed.
   306  //
   307  // Calling Close multiple times is not an error.
   308  func (conn *Conn) Close() error {
   309  	conn.mutex.Lock()
   310  	if conn.closing {
   311  		conn.mutex.Unlock()
   312  		// Golang's net/rpc returns rpc.ErrShutdown if you ask to close
   313  		// a closing or shutdown connection. Our choice is that Close
   314  		// is an idempotent way to ask for resources to be released and
   315  		// isn't a failure if called multiple times.
   316  		return nil
   317  	}
   318  	conn.closing = true
   319  	conn.killRequests()
   320  	conn.mutex.Unlock()
   321  
   322  	// Wait for any outstanding server requests to complete
   323  	// and write their replies before closing the codec.
   324  	conn.srvPending.Wait()
   325  
   326  	// Closing the codec should cause the input loop to terminate.
   327  	if err := conn.codec.Close(); err != nil {
   328  		logger.Infof("error closing codec: %v", err)
   329  	}
   330  	<-conn.dead
   331  
   332  	conn.mutex.Lock()
   333  	conn.cleanRoot()
   334  	conn.mutex.Unlock()
   335  
   336  	return conn.inputLoopError
   337  }
   338  
   339  // Kill server requests if appropriate. Client requests will be
   340  // terminated when the input loop finishes.
   341  func (conn *Conn) killRequests() {
   342  	if killer, ok := conn.root.(Killer); ok {
   343  		killer.Kill()
   344  	}
   345  }
   346  
   347  func (conn *Conn) cleanRoot() {
   348  	if cleaner, ok := conn.root.(Cleaner); ok {
   349  		cleaner.Cleanup()
   350  	}
   351  }
   352  
   353  // ErrorCoder represents an any error that has an associated
   354  // error code. An error code is a short string that represents the
   355  // kind of an error.
   356  type ErrorCoder interface {
   357  	ErrorCode() string
   358  }
   359  
   360  // MethodFinder represents a type that can be used to lookup a Method and place
   361  // calls on that method.
   362  type MethodFinder interface {
   363  	FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error)
   364  }
   365  
   366  // Killer represents a type that can be asked to abort any outstanding
   367  // requests.  The Kill method should return immediately.
   368  type Killer interface {
   369  	Kill()
   370  }
   371  
   372  // Cleaner represents a type that can be asked to clean up after
   373  // itself once the connection has closed.
   374  type Cleaner interface {
   375  	Cleanup()
   376  }
   377  
   378  // input reads messages from the connection and handles them
   379  // appropriately.
   380  func (conn *Conn) input() {
   381  	err := conn.loop()
   382  	conn.sending.Lock()
   383  	defer conn.sending.Unlock()
   384  	conn.mutex.Lock()
   385  	defer conn.mutex.Unlock()
   386  
   387  	if conn.closing || err == io.EOF {
   388  		err = ErrShutdown
   389  	} else {
   390  		// Make the error available for Conn.Close to see.
   391  		conn.inputLoopError = err
   392  	}
   393  	// Terminate all client requests.
   394  	for _, call := range conn.clientPending {
   395  		call.Error = err
   396  		call.done()
   397  	}
   398  	conn.clientPending = nil
   399  	conn.shutdown = true
   400  	close(conn.dead)
   401  }
   402  
   403  // loop implements the looping part of Conn.input.
   404  func (conn *Conn) loop() error {
   405  	var hdr Header
   406  	for {
   407  		hdr = Header{}
   408  		err := conn.codec.ReadHeader(&hdr)
   409  		if err != nil {
   410  			return err
   411  		}
   412  		if hdr.IsRequest() {
   413  			err = conn.handleRequest(&hdr)
   414  		} else {
   415  			err = conn.handleResponse(&hdr)
   416  		}
   417  		if err != nil {
   418  			return err
   419  		}
   420  	}
   421  }
   422  
   423  func (conn *Conn) readBody(resp interface{}, isRequest bool) error {
   424  	if resp == nil {
   425  		resp = &struct{}{}
   426  	}
   427  	return conn.codec.ReadBody(resp, isRequest)
   428  }
   429  
   430  func (conn *Conn) handleRequest(hdr *Header) error {
   431  	startTime := time.Now()
   432  	req, err := conn.bindRequest(hdr)
   433  	if err != nil {
   434  		if conn.notifier != nil {
   435  			conn.notifier.ServerRequest(hdr, nil)
   436  		}
   437  		if err := conn.readBody(nil, true); err != nil {
   438  			return err
   439  		}
   440  		// We don't transform the error here. bindRequest will have
   441  		// already transformed it and returned a zero req.
   442  		return conn.writeErrorResponse(hdr, err, startTime)
   443  	}
   444  	var argp interface{}
   445  	var arg reflect.Value
   446  	if req.ParamsType() != nil {
   447  		v := reflect.New(req.ParamsType())
   448  		arg = v.Elem()
   449  		argp = v.Interface()
   450  	}
   451  	if err := conn.readBody(argp, true); err != nil {
   452  		if conn.notifier != nil {
   453  			conn.notifier.ServerRequest(hdr, nil)
   454  		}
   455  		// If we get EOF, we know the connection is a
   456  		// goner, so don't try to respond.
   457  		if err == io.EOF || err == io.ErrUnexpectedEOF {
   458  			return err
   459  		}
   460  		// An error reading the body often indicates bad
   461  		// request parameters rather than an issue with
   462  		// the connection itself, so we reply with an
   463  		// error rather than tearing down the connection
   464  		// unless it's obviously a connection issue.  If
   465  		// the error is actually a framing or syntax
   466  		// problem, then the next ReadHeader should pick
   467  		// up the problem and abort.
   468  		return conn.writeErrorResponse(hdr, req.transformErrors(err), startTime)
   469  	}
   470  	if conn.notifier != nil {
   471  		if req.ParamsType() != nil {
   472  			conn.notifier.ServerRequest(hdr, arg.Interface())
   473  		} else {
   474  			conn.notifier.ServerRequest(hdr, struct{}{})
   475  		}
   476  	}
   477  	conn.mutex.Lock()
   478  	closing := conn.closing
   479  	if !closing {
   480  		conn.srvPending.Add(1)
   481  		go conn.runRequest(req, arg, startTime)
   482  	}
   483  	conn.mutex.Unlock()
   484  	if closing {
   485  		// We're closing down - no new requests may be initiated.
   486  		return conn.writeErrorResponse(hdr, req.transformErrors(ErrShutdown), startTime)
   487  	}
   488  	return nil
   489  }
   490  
   491  func (conn *Conn) writeErrorResponse(reqHdr *Header, err error, startTime time.Time) error {
   492  	conn.sending.Lock()
   493  	defer conn.sending.Unlock()
   494  	hdr := &Header{
   495  		RequestId: reqHdr.RequestId,
   496  	}
   497  	if err, ok := err.(ErrorCoder); ok {
   498  		hdr.ErrorCode = err.ErrorCode()
   499  	} else {
   500  		hdr.ErrorCode = ""
   501  	}
   502  	hdr.Error = err.Error()
   503  	if conn.notifier != nil {
   504  		conn.notifier.ServerReply(reqHdr.Request, hdr, struct{}{}, time.Since(startTime))
   505  	}
   506  	return conn.codec.WriteMessage(hdr, struct{}{})
   507  }
   508  
   509  // boundRequest represents an RPC request that is
   510  // bound to an actual implementation.
   511  type boundRequest struct {
   512  	rpcreflect.MethodCaller
   513  	transformErrors func(error) error
   514  	hdr             Header
   515  }
   516  
   517  // bindRequest searches for methods implementing the
   518  // request held in the given header and returns
   519  // a boundRequest that can call those methods.
   520  func (conn *Conn) bindRequest(hdr *Header) (boundRequest, error) {
   521  	conn.mutex.Lock()
   522  	methodFinder := conn.methodFinder
   523  	transformErrors := conn.transformErrors
   524  	conn.mutex.Unlock()
   525  
   526  	if methodFinder == nil {
   527  		return boundRequest{}, fmt.Errorf("no service")
   528  	}
   529  	caller, err := methodFinder.FindMethod(
   530  		hdr.Request.Type, hdr.Request.Version, hdr.Request.Action)
   531  	if err != nil {
   532  		if _, ok := err.(*rpcreflect.CallNotImplementedError); ok {
   533  			err = &serverError{
   534  				Message: err.Error(),
   535  				Code:    CodeNotImplemented,
   536  			}
   537  		} else {
   538  			err = transformErrors(err)
   539  		}
   540  		return boundRequest{}, err
   541  	}
   542  	return boundRequest{
   543  		MethodCaller:    caller,
   544  		transformErrors: transformErrors,
   545  		hdr:             *hdr,
   546  	}, nil
   547  }
   548  
   549  // runRequest runs the given request and sends the reply.
   550  func (conn *Conn) runRequest(req boundRequest, arg reflect.Value, startTime time.Time) {
   551  	defer conn.srvPending.Done()
   552  	rv, err := req.Call(req.hdr.Request.Id, arg)
   553  	if err != nil {
   554  		err = conn.writeErrorResponse(&req.hdr, req.transformErrors(err), startTime)
   555  	} else {
   556  		hdr := &Header{
   557  			RequestId: req.hdr.RequestId,
   558  		}
   559  		var rvi interface{}
   560  		if rv.IsValid() {
   561  			rvi = rv.Interface()
   562  		} else {
   563  			rvi = struct{}{}
   564  		}
   565  		if conn.notifier != nil {
   566  			conn.notifier.ServerReply(req.hdr.Request, hdr, rvi, time.Since(startTime))
   567  		}
   568  		conn.sending.Lock()
   569  		err = conn.codec.WriteMessage(hdr, rvi)
   570  		conn.sending.Unlock()
   571  	}
   572  	if err != nil {
   573  		logger.Errorf("error writing response: %v", err)
   574  	}
   575  }
   576  
   577  type serverError RequestError
   578  
   579  func (e *serverError) Error() string {
   580  	return e.Message
   581  }
   582  
   583  func (e *serverError) ErrorCode() string {
   584  	return e.Code
   585  }