// handleMessage is run from the receive goroutine to process a single // message. m cannot be held onto past the return of handleMessage, and // c.mu is not held at the start of handleMessage. func (c *Conn) handleMessage(m rpccapnp.Message) { switch m.Which() { case rpccapnp.Message_Which_unimplemented: // no-op for now to avoid feedback loop case rpccapnp.Message_Which_abort: a, err := copyAbort(m) if err != nil { c.errorf("decode abort: %v", err) // Keep going, since we're trying to abort anyway. } c.infof("abort: %v", a) c.shutdown(a) case rpccapnp.Message_Which_return: m = copyRPCMessage(m) c.mu.Lock() err := c.handleReturnMessage(m) c.mu.Unlock() if err != nil { c.errorf("handle return: %v", err) } case rpccapnp.Message_Which_finish: mfin, err := m.Finish() if err != nil { c.errorf("decode finish: %v", err) return } id := answerID(mfin.QuestionId()) c.mu.Lock() a := c.popAnswer(id) if a == nil { c.mu.Unlock() c.errorf("finish called for unknown answer %d", id) return } a.cancel() if mfin.ReleaseResultCaps() { for _, id := range a.resultCaps { c.releaseExport(id, 1) } } c.mu.Unlock() case rpccapnp.Message_Which_bootstrap: boot, err := m.Bootstrap() if err != nil { c.errorf("decode bootstrap: %v", err) return } id := answerID(boot.QuestionId()) c.mu.Lock() err = c.handleBootstrapMessage(id) c.mu.Unlock() if err != nil { c.errorf("handle bootstrap: %v", err) } case rpccapnp.Message_Which_call: m = copyRPCMessage(m) c.mu.Lock() err := c.handleCallMessage(m) c.mu.Unlock() if err != nil { c.errorf("handle call: %v", err) } case rpccapnp.Message_Which_release: rel, err := m.Release() if err != nil { c.errorf("decode release: %v", err) return } id := exportID(rel.Id()) refs := int(rel.ReferenceCount()) c.mu.Lock() c.releaseExport(id, refs) c.mu.Unlock() case rpccapnp.Message_Which_disembargo: m = copyRPCMessage(m) c.mu.Lock() err := c.handleDisembargoMessage(m) c.mu.Unlock() if err != nil { // Any failure in a disembargo is a protocol violation. c.abort(err) } default: c.infof("received unimplemented message, which = %v", m.Which()) um := newUnimplementedMessage(nil, m) c.sendMessage(um) } }