in connection.go [530:580]
func (c *Connection) SendSystemError(id uint32, span Span, err error) (sendErr error) {
// Allocate an error frame to be sent over the connection. A nil is
// returned if the frame was successfully sent, otherwise an error is
// returned, and we must release the error frame back to the pool.
frame := c.opts.FramePool.Get()
defer func() {
if sendErr != nil {
c.opts.FramePool.Release(frame)
}
}()
if err := frame.write(&errorMessage{
id: id,
errCode: GetSystemErrorCode(err),
tracing: span,
message: GetSystemErrorMessage(err),
}); err != nil {
// This shouldn't happen - it means writing the errorMessage is broken.
c.log.WithFields(
LogField{"remotePeer", c.remotePeerInfo},
LogField{"id", id},
ErrField(err),
).Warn("Couldn't create outbound frame.")
return fmt.Errorf("failed to create outbound error frame: %v", err)
}
// When sending errors, we hold the state rlock to ensure that sendCh is not closed
// as we are sending the frame.
return c.withStateRLock(func() error {
// Errors cannot be sent if the connection has been closed.
if c.state == connectionClosed {
c.log.WithFields(
LogField{"remotePeer", c.remotePeerInfo},
LogField{"id", id},
).Info("Could not send error frame on closed connection.")
return fmt.Errorf("failed to send error frame, connection state %v", c.state)
}
select {
case c.sendCh <- frame: // Good to go
return nil
default: // If the send buffer is full, log and return an error.
}
c.log.WithFields(
LogField{"remotePeer", c.remotePeerInfo},
LogField{"id", id},
ErrField(err),
).Warn("Couldn't send outbound frame.")
return fmt.Errorf("failed to send error frame, buffer full")
})
}