Exemple #1
0
// teardown moves the connection from the dying to the dead state.
func (c *Conn) teardown(abort rpccapnp.Message) {
	c.workers.Wait()

	c.mu.Lock()
	for _, q := range c.questions {
		if q != nil {
			q.cancel(ErrConnClosed)
		}
	}
	c.questions = nil
	exps := c.exports
	c.exports = nil
	c.embargoes = nil
	for _, a := range c.answers {
		a.cancel()
	}
	c.answers = nil
	c.imports = nil
	c.mainFunc = nil
	c.mu.Unlock()

	if c.mainCloser != nil {
		if err := c.mainCloser.Close(); err != nil {
			c.errorf("closing main interface: %v", err)
		}
		c.mainCloser = nil
	}
	// Closing an export may try to lock the Conn, so run it outside
	// critical section.
	for id, e := range exps {
		if e == nil {
			continue
		}
		if err := e.client.Close(); err != nil {
			c.errorf("export %v close: %v", id, err)
		}
	}
	exps = nil

	var werr error
	if abort.IsValid() {
		werr = c.transport.SendMessage(context.Background(), abort)
	}
	cerr := c.transport.Close()

	c.stateMu.Lock()
	if c.closeErr == ErrConnClosed {
		if cerr != nil {
			c.closeErr = cerr
		} else if werr != nil {
			c.closeErr = werr
		}
	}
	c.state = connDead
	c.stateCond.Broadcast()
	c.stateMu.Unlock()
}