예제 #1
0
// 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)
		}
	}
}
예제 #2
0
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
	}
}
예제 #3
0
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)
	}
}
예제 #4
0
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)
	}
}
예제 #5
0
// 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)
		}
	}
}
예제 #6
0
// 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)
	}
}
예제 #7
0
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)
	}
}
예제 #8
0
func (h *handler) linkError(l proton.Link, msg string) {
	proton.CloseError(l, amqp.Errorf(amqp.InternalError, "%s for %s %s", msg, l.Type(), l))
}
예제 #9
0
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)
		}
	}
}
예제 #10
0
func (h *handler) internalError(ep proton.Endpoint, msg string) {
	proton.CloseError(ep, amqp.Errorf(amqp.InternalError, "%s %s", msg, ep))
}
예제 #11
0
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
	}
}