// handleReturnMessage is to handle a received return message. // The caller is holding onto c.mu. func (c *Conn) handleReturnMessage(m rpccapnp.Message) error { ret, err := m.Return() if err != nil { return err } id := questionID(ret.AnswerId()) q := c.popQuestion(id) if q == nil { return fmt.Errorf("received return for unknown question id=%d", id) } if ret.ReleaseParamCaps() { for _, id := range q.paramCaps { c.releaseExport(id, 1) } } q.mu.RLock() qstate := q.state q.mu.RUnlock() if qstate == questionCanceled { // We already sent the finish message. return nil } releaseResultCaps := true switch ret.Which() { case rpccapnp.Return_Which_results: releaseResultCaps = false results, err := ret.Results() if err != nil { return err } if err := c.populateMessageCapTable(results); err == errUnimplemented { um := newUnimplementedMessage(nil, m) c.sendMessage(um) return errUnimplemented } else if err != nil { c.abort(err) return err } content, err := results.ContentPtr() if err != nil { return err } q.fulfill(content) case rpccapnp.Return_Which_exception: exc, err := ret.Exception() if err != nil { return err } e := error(Exception{exc}) if q.method != nil { e = &capnp.MethodError{ Method: q.method, Err: e, } } else { e = bootstrapError{e} } q.reject(e) case rpccapnp.Return_Which_canceled: err := &questionError{ id: id, method: q.method, err: fmt.Errorf("receiver reported canceled"), } c.errorf("%v", err) q.reject(err) return nil default: um := newUnimplementedMessage(nil, m) c.sendMessage(um) return errUnimplemented } fin := newFinishMessage(nil, id, releaseResultCaps) c.sendMessage(fin) return nil }