Ejemplo n.º 1
0
// 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)
	}
}