// HandleMessagingEvent handles an event, called in the handler goroutine. func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MStart: h.injecter = e.Injecter() case proton.MLinkOpening: if e.Link().IsReceiver() { h.startReceiver(e) } else { h.startSender(e) } case proton.MLinkClosed: h.linkClosed(e.Link(), e.Link().RemoteCondition().Error()) case proton.MSendable: if s, ok := h.senders[e.Link()]; ok { s.sendable() // Signal the send goroutine that we have credit. } else { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s sender not found", e.Link())) } case proton.MMessage: m, err := e.Delivery().Message() // Message() must be called while handling the MMessage event. if err != nil { proton.CloseError(e.Link(), err) break } r, ok := h.receivers[e.Link()] if !ok { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s receiver not found", e.Link())) break } // This will not block as AMQP credit is set to the buffer capacity. r.buffer <- receivedMessage{e.Delivery(), m} util.Debugf("link %s received %s", e.Link(), util.FormatMessage(m)) case proton.MConnectionClosed, proton.MDisconnected: for l, _ := range h.receivers { h.linkClosed(l, nil) } for l, _ := range h.senders { h.linkClosed(l, nil) } } }
func (i *incoming) error(fmt string, arg ...interface{}) error { switch { case i.err != nil: return i.err case !i.accepted: return amqp.Errorf(amqp.NotAllowed, fmt, arg...) default: return nil } }
func (h *handler) incoming(in Incoming) { var err error if h.connection.incoming != nil { h.connection.incoming <- in err = in.wait() } else { err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s", in.pEndpoint().Type(), in.pEndpoint().String()) } if err == nil { in.pEndpoint().Open() } else { proton.CloseError(in.pEndpoint(), err) } }
func (h *handler) incoming(in Incoming) { var err error if h.connection.incoming != nil { h.connection.incoming <- in // Must block until accept/reject, subsequent events may use the incoming endpoint. err = in.wait() } else { err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s", in.pEndpoint().Type(), in.pEndpoint().String()) } if err == nil { in.pEndpoint().Open() } else { proton.CloseError(in.pEndpoint(), err) } }
// Test closing the client end of the connection. func TestConnectionCloseInterrupt2(t *testing.T) { want := amqp.Errorf("x", "bad") pairs := newPairs(t) results := make(chan result) // Collect expected errors // Connection.Close() interrupts Send, Receive, Disposition. snd, rcv := pairs.senderReceiver() go doReceive(rcv, results) sm, err := snd.Send(amqp.NewMessage()) fatalIf(t, err) go doDisposition(sm, results) snd, rcv = pairs.senderReceiver() go doSend(snd, results) rcv, snd = pairs.receiverSender() go doReceive(rcv, results) pairs.client.Close(want) for i := 0; i < 3; i++ { if r := <-results; want != r.err { // TODO aconway 2015-10-06: Not propagating the correct error, seeing nil. t.Logf("want %v got %v", want, r.err) } } }
// Test that closing Links interrupts blocked link functions. func TestLinkCloseInterrupt(t *testing.T) { want := amqp.Errorf("x", "all bad") pairs := newPairs(t) results := make(chan result) // Collect expected errors // Sender.Close() interrupts Send() snd, rcv := pairs.senderReceiver() go doSend(snd, results) snd.Close(want) if r := <-results; want != r.err { t.Errorf("want %#v got %#v", want, r) } // Remote Receiver.Close() interrupts Send() snd, rcv = pairs.senderReceiver() go doSend(snd, results) rcv.Close(want) if r := <-results; want != r.err { t.Errorf("want %#v got %#v", want, r) } // Receiver.Close() interrupts Receive() snd, rcv = pairs.senderReceiver() go doReceive(rcv, results) rcv.Close(want) if r := <-results; want != r.err { t.Errorf("want %#v got %#v", want, r) } // Remote Sender.Close() interrupts Receive() snd, rcv = pairs.senderReceiver() go doReceive(rcv, results) snd.Close(want) if r := <-results; want != r.err { t.Errorf("want %#v got %#v", want, r) } }
func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MMessage: if r, ok := h.links[e.Link()].(*receiver); ok { r.message(e.Delivery()) } else { h.linkError(e.Link(), "no receiver") } case proton.MSettled: if sm, ok := h.sentMessages[e.Delivery()]; ok { d := e.Delivery().Remote() sm.ack <- Outcome{sentStatus(d.Type()), d.Condition().Error(), sm.value} delete(h.sentMessages, e.Delivery()) } case proton.MSendable: if s, ok := h.links[e.Link()].(*sender); ok { s.sendable() } else { h.linkError(e.Link(), "no sender") } case proton.MConnectionOpening: h.connection.heartbeat = e.Transport().RemoteIdleTimeout() if e.Connection().State().LocalUninit() { // Remotely opened h.incoming(newIncomingConnection(h.connection)) } h.connection.wakeSync() case proton.MSessionOpening: if e.Session().State().LocalUninit() { // Remotely opened h.incoming(newIncomingSession(h, e.Session())) } h.sessions[e.Session()].wakeSync() case proton.MSessionClosed: h.sessionClosed(e.Session(), proton.EndpointError(e.Session())) case proton.MLinkOpening: l := e.Link() if ss := h.sessions[l.Session()]; ss != nil { if l.State().LocalUninit() { // Remotely opened. if l.IsReceiver() { h.incoming(newIncomingReceiver(ss, l)) } else { h.incoming(newIncomingSender(ss, l)) } } if ep, ok := h.links[l]; ok { ep.wakeSync() } else { h.linkError(l, "no link") } } else { h.linkError(l, "no session") } case proton.MLinkClosing: e.Link().Close() case proton.MLinkClosed: h.linkClosed(e.Link(), proton.EndpointError(e.Link())) case proton.MConnectionClosing: h.connection.err.Set(e.Connection().RemoteCondition().Error()) case proton.MConnectionClosed: h.shutdown(proton.EndpointError(e.Connection())) case proton.MDisconnected: err := e.Transport().Condition().Error() if err == nil { err = amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection) } h.shutdown(err) } }
func (h *handler) linkError(l proton.Link, msg string) { proton.CloseError(l, amqp.Errorf(amqp.InternalError, "%s for %s %s", msg, l.Type(), l)) }
func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MMessage: if r, ok := h.links[e.Link()].(*receiver); ok { r.message(e.Delivery()) } else { h.internalError(e.Link(), "no receiver for link") } case proton.MSettled: if sm := h.sentMessages[e.Delivery()]; sm != nil { sm.settled(nil) } case proton.MSendable: if s, ok := h.links[e.Link()].(*sender); ok { s.sendable() } else { h.internalError(e.Link(), "no sender for link") } case proton.MSessionOpening: if e.Session().State().LocalUninit() { // Remotely opened incoming := &IncomingSession{h: h, pSession: e.Session()} h.connection.accept(incoming) if err := incoming.error("rejected session %s", e.Session()); err != nil { proton.CloseError(e.Session(), err) } } case proton.MSessionClosed: err := proton.EndpointError(e.Session()) for l, _ := range h.links { if l.Session() == e.Session() { h.linkClosed(l, err) } } delete(h.sessions, e.Session()) case proton.MLinkOpening: l := e.Link() if l.State().LocalActive() { // Already opened locally. break } ss := h.sessions[l.Session()] if ss == nil { h.internalError(e.Link(), "no session for link") break } var incoming Incoming if l.IsReceiver() { incoming = &IncomingReceiver{makeIncomingLink(ss, l)} } else { incoming = &IncomingSender{makeIncomingLink(ss, l)} } h.connection.accept(incoming) if err := incoming.error("rejected link %s", e.Link()); err != nil { proton.CloseError(l, err) break } case proton.MLinkClosing: e.Link().Close() case proton.MLinkClosed: h.linkClosed(e.Link(), proton.EndpointError(e.Link())) case proton.MConnectionClosing: h.connection.err.Set(e.Connection().RemoteCondition().Error()) case proton.MConnectionClosed: h.connection.err.Set(Closed) // If no error already set, this is an orderly close. case proton.MDisconnected: h.connection.err.Set(e.Transport().Condition().Error()) // If err not set at this point (e.g. to Closed) then this is unexpected. h.connection.err.Set(amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection)) err := h.connection.Error() for l, _ := range h.links { h.linkClosed(l, err) } for _, s := range h.sessions { s.closed(err) } for _, sm := range h.sentMessages { sm.settled(err) } } }
func (h *handler) internalError(ep proton.Endpoint, msg string) { proton.CloseError(ep, amqp.Errorf(amqp.InternalError, "%s %s", msg, ep)) }
func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MMessage: if r, ok := h.links[e.Link()].(*receiver); ok { r.message(e.Delivery()) } else { h.linkError(e.Link(), "no receiver") } case proton.MSettled: if sm, ok := h.sentMessages[e.Delivery()]; ok { d := e.Delivery().Remote() sm.ack <- Outcome{sentStatus(d.Type()), d.Condition().Error(), sm.value} delete(h.sentMessages, e.Delivery()) } case proton.MSendable: if s, ok := h.links[e.Link()].(*sender); ok { s.sendable() } else { h.linkError(e.Link(), "no sender") } case proton.MSessionOpening: if e.Session().State().LocalUninit() { // Remotely opened h.incoming(newIncomingSession(h, e.Session())) } case proton.MSessionClosed: h.sessionClosed(e.Session(), proton.EndpointError(e.Session())) case proton.MLinkOpening: l := e.Link() if l.State().LocalActive() { // Already opened locally. break } ss := h.sessions[l.Session()] if ss == nil { h.linkError(e.Link(), "no session") break } if l.IsReceiver() { h.incoming(&IncomingReceiver{makeIncomingLink(ss, l)}) } else { h.incoming(&IncomingSender{makeIncomingLink(ss, l)}) } case proton.MLinkClosing: e.Link().Close() case proton.MLinkClosed: h.linkClosed(e.Link(), proton.EndpointError(e.Link())) case proton.MConnectionClosing: h.connection.err.Set(e.Connection().RemoteCondition().Error()) case proton.MConnectionClosed: h.connectionClosed(proton.EndpointError(e.Connection())) case proton.MDisconnected: h.connection.err.Set(e.Transport().Condition().Error()) // If err not set at this point (e.g. to Closed) then this is unexpected. h.connection.err.Set(amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection)) err := h.connection.Error() for l, _ := range h.links { h.linkClosed(l, err) } h.links = nil for _, s := range h.sessions { s.closed(err) } h.sessions = nil for _, sm := range h.sentMessages { sm.ack <- Outcome{Unacknowledged, err, sm.value} } h.sentMessages = nil } }