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 }