зеркало из https://github.com/Azure/go-amqp.git
Move frame types to internal/frames package (#62)
Exported fields on the Frame type. This required moving some dependent constants to the encoding package. ReadBool no longer needs to be exported from encoding. Refactored value() methods on a few constant types to avoid them from being part of public surface area.
This commit is contained in:
Родитель
ea76cacf01
Коммит
7fe27c31cd
15
client.go
15
client.go
|
@ -11,6 +11,9 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -127,7 +130,7 @@ func (c *Client) NewSession(opts ...SessionOption) (*Session, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Begin to server
|
// send Begin to server
|
||||||
begin := &performBegin{
|
begin := &frames.PerformBegin{
|
||||||
NextOutgoingID: 0,
|
NextOutgoingID: 0,
|
||||||
IncomingWindow: s.incomingWindow,
|
IncomingWindow: s.incomingWindow,
|
||||||
OutgoingWindow: s.outgoingWindow,
|
OutgoingWindow: s.outgoingWindow,
|
||||||
|
@ -137,18 +140,18 @@ func (c *Client) NewSession(opts ...SessionOption) (*Session, error) {
|
||||||
_ = s.txFrame(begin, nil)
|
_ = s.txFrame(begin, nil)
|
||||||
|
|
||||||
// wait for response
|
// wait for response
|
||||||
var fr frame
|
var fr frames.Frame
|
||||||
select {
|
select {
|
||||||
case <-c.conn.done:
|
case <-c.conn.done:
|
||||||
return nil, c.conn.getErr()
|
return nil, c.conn.getErr()
|
||||||
case fr = <-s.rx:
|
case fr = <-s.rx:
|
||||||
}
|
}
|
||||||
debug(1, "RX: %s", fr.body)
|
debug(1, "RX: %s", fr.Body)
|
||||||
|
|
||||||
begin, ok := fr.body.(*performBegin)
|
begin, ok := fr.Body.(*frames.PerformBegin)
|
||||||
if !ok {
|
if !ok {
|
||||||
_ = s.Close(context.Background()) // deallocate session on error
|
_ = s.Close(context.Background()) // deallocate session on error
|
||||||
return nil, fmt.Errorf("unexpected begin response: %+v", fr.body)
|
return nil, fmt.Errorf("unexpected begin response: %+v", fr.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start Session multiplexor
|
// start Session multiplexor
|
||||||
|
@ -255,7 +258,7 @@ const (
|
||||||
// to a boolean flag indicating the direction of the link.
|
// to a boolean flag indicating the direction of the link.
|
||||||
type linkKey struct {
|
type linkKey struct {
|
||||||
name string
|
name string
|
||||||
role role // Local role: sender/receiver
|
role encoding.Role // Local role: sender/receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxTransferFrameHeader = 66 // determined by calcMaxTransferFrameHeader
|
const maxTransferFrameHeader = 66 // determined by calcMaxTransferFrameHeader
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLinkOptions(t *testing.T) {
|
func TestLinkOptions(t *testing.T) {
|
||||||
|
@ -12,7 +13,7 @@ func TestLinkOptions(t *testing.T) {
|
||||||
label string
|
label string
|
||||||
opts []LinkOption
|
opts []LinkOption
|
||||||
|
|
||||||
wantSource *source
|
wantSource *frames.Source
|
||||||
wantProperties map[encoding.Symbol]interface{}
|
wantProperties map[encoding.Symbol]interface{}
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,7 @@ func TestLinkOptions(t *testing.T) {
|
||||||
LinkSourceFilter("com.microsoft:session-filter", 0x00000137000000C, "123"),
|
LinkSourceFilter("com.microsoft:session-filter", 0x00000137000000C, "123"),
|
||||||
},
|
},
|
||||||
|
|
||||||
wantSource: &source{
|
wantSource: &frames.Source{
|
||||||
Filter: map[encoding.Symbol]*encoding.DescribedType{
|
Filter: map[encoding.Symbol]*encoding.DescribedType{
|
||||||
"apache.org:selector-filter:string": {
|
"apache.org:selector-filter:string": {
|
||||||
Descriptor: binary.BigEndian.Uint64([]byte{0x00, 0x00, 0x46, 0x8C, 0x00, 0x00, 0x00, 0x04}),
|
Descriptor: binary.BigEndian.Uint64([]byte{0x00, 0x00, 0x46, 0x8C, 0x00, 0x00, 0x00, 0x04}),
|
||||||
|
@ -55,7 +56,7 @@ func TestLinkOptions(t *testing.T) {
|
||||||
LinkSourceFilter("com.microsoft:session-filter", 0x00000137000000C, nil),
|
LinkSourceFilter("com.microsoft:session-filter", 0x00000137000000C, nil),
|
||||||
},
|
},
|
||||||
|
|
||||||
wantSource: &source{
|
wantSource: &frames.Source{
|
||||||
Filter: map[encoding.Symbol]*encoding.DescribedType{
|
Filter: map[encoding.Symbol]*encoding.DescribedType{
|
||||||
"com.microsoft:session-filter": {
|
"com.microsoft:session-filter": {
|
||||||
Descriptor: binary.BigEndian.Uint64([]byte{0x00, 0x00, 0x00, 0x13, 0x70, 0x00, 0x00, 0x0C}),
|
Descriptor: binary.BigEndian.Uint64([]byte{0x00, 0x00, 0x00, 0x13, 0x70, 0x00, 0x00, 0x0C}),
|
||||||
|
@ -69,7 +70,7 @@ func TestLinkOptions(t *testing.T) {
|
||||||
opts: []LinkOption{
|
opts: []LinkOption{
|
||||||
LinkSourceCapabilities("cap1", "cap2", "cap3"),
|
LinkSourceCapabilities("cap1", "cap2", "cap3"),
|
||||||
},
|
},
|
||||||
wantSource: &source{
|
wantSource: &frames.Source{
|
||||||
Capabilities: []encoding.Symbol{"cap1", "cap2", "cap3"},
|
Capabilities: []encoding.Symbol{"cap1", "cap2", "cap3"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
103
conn.go
103
conn.go
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default connection options
|
// Default connection options
|
||||||
|
@ -203,12 +204,12 @@ type conn struct {
|
||||||
|
|
||||||
// connReader
|
// connReader
|
||||||
rxProto chan protoHeader // protoHeaders received by connReader
|
rxProto chan protoHeader // protoHeaders received by connReader
|
||||||
rxFrame chan frame // AMQP frames received by connReader
|
rxFrame chan frames.Frame // AMQP frames received by connReader
|
||||||
rxDone chan struct{}
|
rxDone chan struct{}
|
||||||
connReaderRun chan func() // functions to be run by conn reader (set deadline on conn to run)
|
connReaderRun chan func() // functions to be run by conn reader (set deadline on conn to run)
|
||||||
|
|
||||||
// connWriter
|
// connWriter
|
||||||
txFrame chan frame // AMQP frames to be sent by connWriter
|
txFrame chan frames.Frame // AMQP frames to be sent by connWriter
|
||||||
txBuf buffer.Buffer // buffer for marshaling frames before transmitting
|
txBuf buffer.Buffer // buffer for marshaling frames before transmitting
|
||||||
txDone chan struct{}
|
txDone chan struct{}
|
||||||
}
|
}
|
||||||
|
@ -230,12 +231,12 @@ func newConn(netConn net.Conn, opts ...ConnOption) (*conn, error) {
|
||||||
connErr: make(chan error, 2), // buffered to ensure connReader/Writer won't leak
|
connErr: make(chan error, 2), // buffered to ensure connReader/Writer won't leak
|
||||||
closeMux: make(chan struct{}),
|
closeMux: make(chan struct{}),
|
||||||
rxProto: make(chan protoHeader),
|
rxProto: make(chan protoHeader),
|
||||||
rxFrame: make(chan frame),
|
rxFrame: make(chan frames.Frame),
|
||||||
rxDone: make(chan struct{}),
|
rxDone: make(chan struct{}),
|
||||||
connReaderRun: make(chan func(), 1), // buffered to allow queueing function before interrupt
|
connReaderRun: make(chan func(), 1), // buffered to allow queueing function before interrupt
|
||||||
newSession: make(chan newSessionResp),
|
newSession: make(chan newSessionResp),
|
||||||
delSession: make(chan *Session),
|
delSession: make(chan *Session),
|
||||||
txFrame: make(chan frame),
|
txFrame: make(chan frames.Frame),
|
||||||
txDone: make(chan struct{}),
|
txDone: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,9 +366,9 @@ func (c *conn) mux() {
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
|
|
||||||
switch body := fr.body.(type) {
|
switch body := fr.Body.(type) {
|
||||||
// Server initiated close.
|
// Server initiated close.
|
||||||
case *performClose:
|
case *frames.PerformClose:
|
||||||
if body.Error != nil {
|
if body.Error != nil {
|
||||||
c.err = body.Error
|
c.err = body.Error
|
||||||
} else {
|
} else {
|
||||||
|
@ -376,7 +377,7 @@ func (c *conn) mux() {
|
||||||
return
|
return
|
||||||
|
|
||||||
// RemoteChannel should be used when frame is Begin
|
// RemoteChannel should be used when frame is Begin
|
||||||
case *performBegin:
|
case *frames.PerformBegin:
|
||||||
if body.RemoteChannel == nil {
|
if body.RemoteChannel == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -385,15 +386,15 @@ func (c *conn) mux() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
session.remoteChannel = fr.channel
|
session.remoteChannel = fr.Channel
|
||||||
sessionsByRemoteChannel[fr.channel] = session
|
sessionsByRemoteChannel[fr.Channel] = session
|
||||||
|
|
||||||
default:
|
default:
|
||||||
session, ok = sessionsByRemoteChannel[fr.channel]
|
session, ok = sessionsByRemoteChannel[fr.Channel]
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
c.err = fmt.Errorf("unexpected frame: %#v", fr.body)
|
c.err = fmt.Errorf("unexpected frame: %#v", fr.Body)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +568,7 @@ func (c *conn) connReader() {
|
||||||
select {
|
select {
|
||||||
case <-c.done:
|
case <-c.done:
|
||||||
return
|
return
|
||||||
case c.rxFrame <- frame{channel: currentHeader.Channel, body: parsedBody}:
|
case c.rxFrame <- frames.Frame{Channel: currentHeader.Channel, Body: parsedBody}:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,8 +608,8 @@ func (c *conn) connWriter() {
|
||||||
// frame write request
|
// frame write request
|
||||||
case fr := <-c.txFrame:
|
case fr := <-c.txFrame:
|
||||||
err = c.writeFrame(fr)
|
err = c.writeFrame(fr)
|
||||||
if err == nil && fr.done != nil {
|
if err == nil && fr.Done != nil {
|
||||||
close(fr.done)
|
close(fr.Done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// keepalive timer
|
// keepalive timer
|
||||||
|
@ -625,11 +626,11 @@ func (c *conn) connWriter() {
|
||||||
// connection complete
|
// connection complete
|
||||||
case <-c.done:
|
case <-c.done:
|
||||||
// send close
|
// send close
|
||||||
cls := &performClose{}
|
cls := &frames.PerformClose{}
|
||||||
debug(1, "TX: %s", cls)
|
debug(1, "TX: %s", cls)
|
||||||
_ = c.writeFrame(frame{
|
_ = c.writeFrame(frames.Frame{
|
||||||
type_: frameTypeAMQP,
|
Type: frameTypeAMQP,
|
||||||
body: cls,
|
Body: cls,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -638,7 +639,7 @@ func (c *conn) connWriter() {
|
||||||
|
|
||||||
// writeFrame writes a frame to the network, may only be used
|
// writeFrame writes a frame to the network, may only be used
|
||||||
// by connWriter after initial negotiation.
|
// by connWriter after initial negotiation.
|
||||||
func (c *conn) writeFrame(fr frame) error {
|
func (c *conn) writeFrame(fr frames.Frame) error {
|
||||||
if c.connectTimeout != 0 {
|
if c.connectTimeout != 0 {
|
||||||
_ = c.net.SetWriteDeadline(time.Now().Add(c.connectTimeout))
|
_ = c.net.SetWriteDeadline(time.Now().Add(c.connectTimeout))
|
||||||
}
|
}
|
||||||
|
@ -676,7 +677,7 @@ var keepaliveFrame = []byte{0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00}
|
||||||
|
|
||||||
// wantWriteFrame is used by sessions and links to send frame to
|
// wantWriteFrame is used by sessions and links to send frame to
|
||||||
// connWriter.
|
// connWriter.
|
||||||
func (c *conn) wantWriteFrame(fr frame) error {
|
func (c *conn) wantWriteFrame(fr frames.Frame) error {
|
||||||
select {
|
select {
|
||||||
case c.txFrame <- fr:
|
case c.txFrame <- fr:
|
||||||
return nil
|
return nil
|
||||||
|
@ -807,7 +808,7 @@ func (c *conn) startTLS() stateFunc {
|
||||||
// openAMQP round trips the AMQP open performative
|
// openAMQP round trips the AMQP open performative
|
||||||
func (c *conn) openAMQP() stateFunc {
|
func (c *conn) openAMQP() stateFunc {
|
||||||
// send open frame
|
// send open frame
|
||||||
open := &performOpen{
|
open := &frames.PerformOpen{
|
||||||
ContainerID: c.containerID,
|
ContainerID: c.containerID,
|
||||||
Hostname: c.hostname,
|
Hostname: c.hostname,
|
||||||
MaxFrameSize: c.maxFrameSize,
|
MaxFrameSize: c.maxFrameSize,
|
||||||
|
@ -816,10 +817,10 @@ func (c *conn) openAMQP() stateFunc {
|
||||||
Properties: c.properties,
|
Properties: c.properties,
|
||||||
}
|
}
|
||||||
debug(1, "TX: %s", open)
|
debug(1, "TX: %s", open)
|
||||||
c.err = c.writeFrame(frame{
|
c.err = c.writeFrame(frames.Frame{
|
||||||
type_: frameTypeAMQP,
|
Type: frameTypeAMQP,
|
||||||
body: open,
|
Body: open,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
})
|
})
|
||||||
if c.err != nil {
|
if c.err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -831,9 +832,9 @@ func (c *conn) openAMQP() stateFunc {
|
||||||
c.err = err
|
c.err = err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
o, ok := fr.body.(*performOpen)
|
o, ok := fr.Body.(*frames.PerformOpen)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.err = fmt.Errorf("unexpected frame type %T", fr.body)
|
c.err = fmt.Errorf("unexpected frame type %T", fr.Body)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
debug(1, "RX: %s", o)
|
debug(1, "RX: %s", o)
|
||||||
|
@ -863,9 +864,9 @@ func (c *conn) negotiateSASL() stateFunc {
|
||||||
c.err = err
|
c.err = err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sm, ok := fr.body.(*saslMechanisms)
|
sm, ok := fr.Body.(*frames.SASLMechanisms)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.err = fmt.Errorf("unexpected frame type %T", fr.body)
|
c.err = fmt.Errorf("unexpected frame type %T", fr.Body)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
debug(1, "RX: %s", sm)
|
debug(1, "RX: %s", sm)
|
||||||
|
@ -894,15 +895,15 @@ func (c *conn) saslOutcome() stateFunc {
|
||||||
c.err = err
|
c.err = err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
so, ok := fr.body.(*saslOutcome)
|
so, ok := fr.Body.(*frames.SASLOutcome)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.err = fmt.Errorf("unexpected frame type %T", fr.body)
|
c.err = fmt.Errorf("unexpected frame type %T", fr.Body)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
debug(1, "RX: %s", so)
|
debug(1, "RX: %s", so)
|
||||||
|
|
||||||
// check if auth succeeded
|
// check if auth succeeded
|
||||||
if so.Code != codeSASLOK {
|
if so.Code != encoding.CodeSASLOK {
|
||||||
c.err = fmt.Errorf("SASL PLAIN auth failed with code %#00x: %s", so.Code, so.AdditionalData) // implement Stringer for so.Code
|
c.err = fmt.Errorf("SASL PLAIN auth failed with code %#00x: %s", so.Code, so.AdditionalData) // implement Stringer for so.Code
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -915,13 +916,13 @@ func (c *conn) saslOutcome() stateFunc {
|
||||||
// readFrame is used during connection establishment to read a single frame.
|
// readFrame is used during connection establishment to read a single frame.
|
||||||
//
|
//
|
||||||
// After setup, conn.mux handles incoming frames.
|
// After setup, conn.mux handles incoming frames.
|
||||||
func (c *conn) readFrame() (frame, error) {
|
func (c *conn) readFrame() (frames.Frame, error) {
|
||||||
var deadline <-chan time.Time
|
var deadline <-chan time.Time
|
||||||
if c.connectTimeout != 0 {
|
if c.connectTimeout != 0 {
|
||||||
deadline = time.After(c.connectTimeout)
|
deadline = time.After(c.connectTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fr frame
|
var fr frames.Frame
|
||||||
select {
|
select {
|
||||||
case fr = <-c.rxFrame:
|
case fr = <-c.rxFrame:
|
||||||
return fr, nil
|
return fr, nil
|
||||||
|
@ -1020,7 +1021,7 @@ func parseProtoHeader(r *buffer.Buffer) (protoHeader, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFrameBody reads and unmarshals an AMQP frame.
|
// parseFrameBody reads and unmarshals an AMQP frame.
|
||||||
func parseFrameBody(r *buffer.Buffer) (frameBody, error) {
|
func parseFrameBody(r *buffer.Buffer) (frames.FrameBody, error) {
|
||||||
payload := r.Bytes()
|
payload := r.Bytes()
|
||||||
|
|
||||||
if r.Len() < 3 || payload[0] != 0 || encoding.AMQPType(payload[1]) != encoding.TypeCodeSmallUlong {
|
if r.Len() < 3 || payload[0] != 0 || encoding.AMQPType(payload[1]) != encoding.TypeCodeSmallUlong {
|
||||||
|
@ -1029,51 +1030,51 @@ func parseFrameBody(r *buffer.Buffer) (frameBody, error) {
|
||||||
|
|
||||||
switch pType := encoding.AMQPType(payload[2]); pType {
|
switch pType := encoding.AMQPType(payload[2]); pType {
|
||||||
case encoding.TypeCodeOpen:
|
case encoding.TypeCodeOpen:
|
||||||
t := new(performOpen)
|
t := new(frames.PerformOpen)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeBegin:
|
case encoding.TypeCodeBegin:
|
||||||
t := new(performBegin)
|
t := new(frames.PerformBegin)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeAttach:
|
case encoding.TypeCodeAttach:
|
||||||
t := new(performAttach)
|
t := new(frames.PerformAttach)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeFlow:
|
case encoding.TypeCodeFlow:
|
||||||
t := new(performFlow)
|
t := new(frames.PerformFlow)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeTransfer:
|
case encoding.TypeCodeTransfer:
|
||||||
t := new(performTransfer)
|
t := new(frames.PerformTransfer)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeDisposition:
|
case encoding.TypeCodeDisposition:
|
||||||
t := new(performDisposition)
|
t := new(frames.PerformDisposition)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeDetach:
|
case encoding.TypeCodeDetach:
|
||||||
t := new(performDetach)
|
t := new(frames.PerformDetach)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeEnd:
|
case encoding.TypeCodeEnd:
|
||||||
t := new(performEnd)
|
t := new(frames.PerformEnd)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeClose:
|
case encoding.TypeCodeClose:
|
||||||
t := new(performClose)
|
t := new(frames.PerformClose)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeSASLMechanism:
|
case encoding.TypeCodeSASLMechanism:
|
||||||
t := new(saslMechanisms)
|
t := new(frames.SASLMechanisms)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeSASLChallenge:
|
case encoding.TypeCodeSASLChallenge:
|
||||||
t := new(saslChallenge)
|
t := new(frames.SASLChallenge)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
case encoding.TypeCodeSASLOutcome:
|
case encoding.TypeCodeSASLOutcome:
|
||||||
t := new(saslOutcome)
|
t := new(frames.SASLOutcome)
|
||||||
err := t.Unmarshal(r)
|
err := t.Unmarshal(r)
|
||||||
return t, err
|
return t, err
|
||||||
default:
|
default:
|
||||||
|
@ -1082,17 +1083,17 @@ func parseFrameBody(r *buffer.Buffer) (frameBody, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// writesFrame encodes fr into buf.
|
// writesFrame encodes fr into buf.
|
||||||
func writeFrame(buf *buffer.Buffer, fr frame) error {
|
func writeFrame(buf *buffer.Buffer, fr frames.Frame) error {
|
||||||
// write header
|
// write header
|
||||||
buf.Append([]byte{
|
buf.Append([]byte{
|
||||||
0, 0, 0, 0, // size, overwrite later
|
0, 0, 0, 0, // size, overwrite later
|
||||||
2, // doff, see frameHeader.DataOffset comment
|
2, // doff, see frameHeader.DataOffset comment
|
||||||
fr.type_, // frame type
|
fr.Type, // frame type
|
||||||
})
|
})
|
||||||
buf.AppendUint16(fr.channel) // channel
|
buf.AppendUint16(fr.Channel) // channel
|
||||||
|
|
||||||
// write AMQP frame body
|
// write AMQP frame body
|
||||||
err := encoding.Marshal(buf, fr.body)
|
err := encoding.Marshal(buf, fr.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
156
const.go
156
const.go
|
@ -1,58 +1,23 @@
|
||||||
package amqp
|
package amqp
|
||||||
|
|
||||||
import (
|
import "github.com/Azure/go-amqp/internal/encoding"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Sender Settlement Modes
|
// Sender Settlement Modes
|
||||||
const (
|
const (
|
||||||
// Sender will send all deliveries initially unsettled to the receiver.
|
// Sender will send all deliveries initially unsettled to the receiver.
|
||||||
ModeUnsettled SenderSettleMode = 0
|
ModeUnsettled = encoding.ModeUnsettled
|
||||||
|
|
||||||
// Sender will send all deliveries settled to the receiver.
|
// Sender will send all deliveries settled to the receiver.
|
||||||
ModeSettled SenderSettleMode = 1
|
ModeSettled = encoding.ModeSettled
|
||||||
|
|
||||||
// Sender MAY send a mixture of settled and unsettled deliveries to the receiver.
|
// Sender MAY send a mixture of settled and unsettled deliveries to the receiver.
|
||||||
ModeMixed SenderSettleMode = 2
|
ModeMixed = encoding.ModeMixed
|
||||||
)
|
)
|
||||||
|
|
||||||
// SenderSettleMode specifies how the sender will settle messages.
|
// SenderSettleMode specifies how the sender will settle messages.
|
||||||
type SenderSettleMode uint8
|
type SenderSettleMode = encoding.SenderSettleMode
|
||||||
|
|
||||||
func (m *SenderSettleMode) String() string {
|
func senderSettleModeValue(m *SenderSettleMode) SenderSettleMode {
|
||||||
if m == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *m {
|
|
||||||
case ModeUnsettled:
|
|
||||||
return "unsettled"
|
|
||||||
|
|
||||||
case ModeSettled:
|
|
||||||
return "settled"
|
|
||||||
|
|
||||||
case ModeMixed:
|
|
||||||
return "mixed"
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown sender mode %d", uint8(*m))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m SenderSettleMode) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Marshal(wr, uint8(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SenderSettleMode) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
n, err := encoding.ReadUbyte(r)
|
|
||||||
*m = SenderSettleMode(n)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SenderSettleMode) value() SenderSettleMode {
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return ModeMixed
|
return ModeMixed
|
||||||
}
|
}
|
||||||
|
@ -62,45 +27,18 @@ func (m *SenderSettleMode) value() SenderSettleMode {
|
||||||
// Receiver Settlement Modes
|
// Receiver Settlement Modes
|
||||||
const (
|
const (
|
||||||
// Receiver will spontaneously settle all incoming transfers.
|
// Receiver will spontaneously settle all incoming transfers.
|
||||||
ModeFirst ReceiverSettleMode = 0
|
ModeFirst = encoding.ModeFirst
|
||||||
|
|
||||||
// Receiver will only settle after sending the disposition to the
|
// Receiver will only settle after sending the disposition to the
|
||||||
// sender and receiving a disposition indicating settlement of
|
// sender and receiving a disposition indicating settlement of
|
||||||
// the delivery from the sender.
|
// the delivery from the sender.
|
||||||
ModeSecond ReceiverSettleMode = 1
|
ModeSecond = encoding.ModeSecond
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReceiverSettleMode specifies how the receiver will settle messages.
|
// ReceiverSettleMode specifies how the receiver will settle messages.
|
||||||
type ReceiverSettleMode uint8
|
type ReceiverSettleMode = encoding.ReceiverSettleMode
|
||||||
|
|
||||||
func (m *ReceiverSettleMode) String() string {
|
func receiverSettleModeValue(m *ReceiverSettleMode) ReceiverSettleMode {
|
||||||
if m == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *m {
|
|
||||||
case ModeFirst:
|
|
||||||
return "first"
|
|
||||||
|
|
||||||
case ModeSecond:
|
|
||||||
return "second"
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown receiver mode %d", uint8(*m))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m ReceiverSettleMode) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Marshal(wr, uint8(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ReceiverSettleMode) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
n, err := encoding.ReadUbyte(r)
|
|
||||||
*m = ReceiverSettleMode(n)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ReceiverSettleMode) value() ReceiverSettleMode {
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return ModeFirst
|
return ModeFirst
|
||||||
}
|
}
|
||||||
|
@ -110,61 +48,36 @@ func (m *ReceiverSettleMode) value() ReceiverSettleMode {
|
||||||
// Durability Policies
|
// Durability Policies
|
||||||
const (
|
const (
|
||||||
// No terminus state is retained durably.
|
// No terminus state is retained durably.
|
||||||
DurabilityNone Durability = 0
|
DurabilityNone = encoding.DurabilityNone
|
||||||
|
|
||||||
// Only the existence and configuration of the terminus is
|
// Only the existence and configuration of the terminus is
|
||||||
// retained durably.
|
// retained durably.
|
||||||
DurabilityConfiguration Durability = 1
|
DurabilityConfiguration = encoding.DurabilityConfiguration
|
||||||
|
|
||||||
// In addition to the existence and configuration of the
|
// In addition to the existence and configuration of the
|
||||||
// terminus, the unsettled state for durable messages is
|
// terminus, the unsettled state for durable messages is
|
||||||
// retained durably.
|
// retained durably.
|
||||||
DurabilityUnsettledState Durability = 2
|
DurabilityUnsettledState = encoding.DurabilityUnsettledState
|
||||||
)
|
)
|
||||||
|
|
||||||
// Durability specifies the durability of a link.
|
// Durability specifies the durability of a link.
|
||||||
type Durability uint32
|
type Durability = encoding.Durability
|
||||||
|
|
||||||
func (d *Durability) String() string {
|
|
||||||
if d == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *d {
|
|
||||||
case DurabilityNone:
|
|
||||||
return "none"
|
|
||||||
case DurabilityConfiguration:
|
|
||||||
return "configuration"
|
|
||||||
case DurabilityUnsettledState:
|
|
||||||
return "unsettled-state"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("unknown durability %d", *d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Durability) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Marshal(wr, uint32(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Durability) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
return encoding.Unmarshal(r, (*uint32)(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expiry Policies
|
// Expiry Policies
|
||||||
const (
|
const (
|
||||||
// The expiry timer starts when terminus is detached.
|
// The expiry timer starts when terminus is detached.
|
||||||
ExpiryLinkDetach ExpiryPolicy = "link-detach"
|
ExpiryLinkDetach = encoding.ExpiryLinkDetach
|
||||||
|
|
||||||
// The expiry timer starts when the most recently
|
// The expiry timer starts when the most recently
|
||||||
// associated session is ended.
|
// associated session is ended.
|
||||||
ExpirySessionEnd ExpiryPolicy = "session-end"
|
ExpirySessionEnd = encoding.ExpirySessionEnd
|
||||||
|
|
||||||
// The expiry timer starts when most recently associated
|
// The expiry timer starts when most recently associated
|
||||||
// connection is closed.
|
// connection is closed.
|
||||||
ExpiryConnectionClose ExpiryPolicy = "connection-close"
|
ExpiryConnectionClose = encoding.ExpiryConnectionClose
|
||||||
|
|
||||||
// The terminus never expires.
|
// The terminus never expires.
|
||||||
ExpiryNever ExpiryPolicy = "never"
|
ExpiryNever = encoding.ExpiryNever
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExpiryPolicy specifies when the expiry timer of a terminus
|
// ExpiryPolicy specifies when the expiry timer of a terminus
|
||||||
|
@ -174,35 +87,4 @@ const (
|
||||||
// then the count down is aborted. If the conditions for the
|
// then the count down is aborted. If the conditions for the
|
||||||
// terminus-expiry-policy are subsequently re-met, the expiry timer restarts
|
// terminus-expiry-policy are subsequently re-met, the expiry timer restarts
|
||||||
// from its originally configured timeout value.
|
// from its originally configured timeout value.
|
||||||
type ExpiryPolicy encoding.Symbol
|
type ExpiryPolicy = encoding.ExpiryPolicy
|
||||||
|
|
||||||
func (e ExpiryPolicy) validate() error {
|
|
||||||
switch e {
|
|
||||||
case ExpiryLinkDetach,
|
|
||||||
ExpirySessionEnd,
|
|
||||||
ExpiryConnectionClose,
|
|
||||||
ExpiryNever:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown expiry-policy %q", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ExpiryPolicy) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Symbol(e).Marshal(wr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExpiryPolicy) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
err := encoding.Unmarshal(r, (*encoding.Symbol)(e))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return e.validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExpiryPolicy) String() string {
|
|
||||||
if e == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
return string(*e)
|
|
||||||
}
|
|
||||||
|
|
67
fuzz_test.go
67
fuzz_test.go
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
"github.com/Azure/go-amqp/internal/testconn"
|
"github.com/Azure/go-amqp/internal/testconn"
|
||||||
"github.com/fortytw2/leaktest"
|
"github.com/fortytw2/leaktest"
|
||||||
)
|
)
|
||||||
|
@ -89,46 +90,44 @@ func fuzzConn(data []byte) int {
|
||||||
|
|
||||||
func fuzzUnmarshal(data []byte) int {
|
func fuzzUnmarshal(data []byte) int {
|
||||||
types := []interface{}{
|
types := []interface{}{
|
||||||
new(performAttach),
|
new(frames.PerformAttach),
|
||||||
new(*performAttach),
|
new(*frames.PerformAttach),
|
||||||
new(performBegin),
|
new(frames.PerformBegin),
|
||||||
new(*performBegin),
|
new(*frames.PerformBegin),
|
||||||
new(performClose),
|
new(frames.PerformClose),
|
||||||
new(*performClose),
|
new(*frames.PerformClose),
|
||||||
new(performDetach),
|
new(frames.PerformDetach),
|
||||||
new(*performDetach),
|
new(*frames.PerformDetach),
|
||||||
new(performDisposition),
|
new(frames.PerformDisposition),
|
||||||
new(*performDisposition),
|
new(*frames.PerformDisposition),
|
||||||
new(performEnd),
|
new(frames.PerformEnd),
|
||||||
new(*performEnd),
|
new(*frames.PerformEnd),
|
||||||
new(performFlow),
|
new(frames.PerformFlow),
|
||||||
new(*performFlow),
|
new(*frames.PerformFlow),
|
||||||
new(performOpen),
|
new(frames.PerformOpen),
|
||||||
new(*performOpen),
|
new(*frames.PerformOpen),
|
||||||
new(performTransfer),
|
new(frames.PerformTransfer),
|
||||||
new(*performTransfer),
|
new(*frames.PerformTransfer),
|
||||||
new(source),
|
new(frames.Source),
|
||||||
new(*source),
|
new(*frames.Source),
|
||||||
new(target),
|
new(frames.Target),
|
||||||
new(*target),
|
new(*frames.Target),
|
||||||
new(saslCode),
|
new(encoding.SASLCode),
|
||||||
new(*saslCode),
|
new(*encoding.SASLCode),
|
||||||
new(saslMechanisms),
|
new(frames.SASLMechanisms),
|
||||||
new(*saslMechanisms),
|
new(*frames.SASLMechanisms),
|
||||||
new(saslChallenge),
|
new(frames.SASLChallenge),
|
||||||
new(*saslChallenge),
|
new(*frames.SASLChallenge),
|
||||||
new(saslResponse),
|
new(frames.SASLResponse),
|
||||||
new(*saslResponse),
|
new(*frames.SASLResponse),
|
||||||
new(saslOutcome),
|
new(frames.SASLOutcome),
|
||||||
new(*saslOutcome),
|
new(*frames.SASLOutcome),
|
||||||
new(Message),
|
new(Message),
|
||||||
new(*Message),
|
new(*Message),
|
||||||
new(MessageHeader),
|
new(MessageHeader),
|
||||||
new(*MessageHeader),
|
new(*MessageHeader),
|
||||||
new(MessageProperties),
|
new(MessageProperties),
|
||||||
new(*MessageProperties),
|
new(*MessageProperties),
|
||||||
new(role),
|
|
||||||
new(*role),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
|
|
|
@ -128,7 +128,7 @@ func Unmarshal(r *buffer.Buffer, i interface{}) error {
|
||||||
}
|
}
|
||||||
*t = val
|
*t = val
|
||||||
case *bool:
|
case *bool:
|
||||||
b, err := ReadBool(r)
|
b, err := readBool(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -494,7 +494,7 @@ func ReadAny(r *buffer.Buffer) (interface{}, error) {
|
||||||
|
|
||||||
// bool
|
// bool
|
||||||
case TypeCodeBool, TypeCodeBoolTrue, TypeCodeBoolFalse:
|
case TypeCodeBool, TypeCodeBoolTrue, TypeCodeBoolFalse:
|
||||||
return ReadBool(r)
|
return readBool(r)
|
||||||
|
|
||||||
// uint
|
// uint
|
||||||
case TypeCodeUbyte:
|
case TypeCodeUbyte:
|
||||||
|
@ -1038,7 +1038,7 @@ func readDouble(r *buffer.Buffer) (float64, error) {
|
||||||
return math.Float64frombits(bits), err
|
return math.Float64frombits(bits), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadBool(r *buffer.Buffer) (bool, error) {
|
func readBool(r *buffer.Buffer) (bool, error) {
|
||||||
type_, err := readType(r)
|
type_, err := readType(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|
|
@ -77,6 +77,8 @@ func fuzzUnmarshal(data []byte) int {
|
||||||
new(*ErrorCondition),
|
new(*ErrorCondition),
|
||||||
new(UUID),
|
new(UUID),
|
||||||
new(*UUID),
|
new(*UUID),
|
||||||
|
new(Role),
|
||||||
|
new(*Role),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
|
|
|
@ -114,6 +114,235 @@ const (
|
||||||
TypeCodeDeleteOnNoLinksOrMessages AMQPType = 0x2e
|
TypeCodeDeleteOnNoLinksOrMessages AMQPType = 0x2e
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Durability Policies
|
||||||
|
const (
|
||||||
|
// No terminus state is retained durably.
|
||||||
|
DurabilityNone Durability = 0
|
||||||
|
|
||||||
|
// Only the existence and configuration of the terminus is
|
||||||
|
// retained durably.
|
||||||
|
DurabilityConfiguration Durability = 1
|
||||||
|
|
||||||
|
// In addition to the existence and configuration of the
|
||||||
|
// terminus, the unsettled state for durable messages is
|
||||||
|
// retained durably.
|
||||||
|
DurabilityUnsettledState Durability = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Durability specifies the durability of a link.
|
||||||
|
type Durability uint32
|
||||||
|
|
||||||
|
func (d *Durability) String() string {
|
||||||
|
if d == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *d {
|
||||||
|
case DurabilityNone:
|
||||||
|
return "none"
|
||||||
|
case DurabilityConfiguration:
|
||||||
|
return "configuration"
|
||||||
|
case DurabilityUnsettledState:
|
||||||
|
return "unsettled-state"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown durability %d", *d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Durability) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Marshal(wr, uint32(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Durability) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
return Unmarshal(r, (*uint32)(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expiry Policies
|
||||||
|
const (
|
||||||
|
// The expiry timer starts when terminus is detached.
|
||||||
|
ExpiryLinkDetach ExpiryPolicy = "link-detach"
|
||||||
|
|
||||||
|
// The expiry timer starts when the most recently
|
||||||
|
// associated session is ended.
|
||||||
|
ExpirySessionEnd ExpiryPolicy = "session-end"
|
||||||
|
|
||||||
|
// The expiry timer starts when most recently associated
|
||||||
|
// connection is closed.
|
||||||
|
ExpiryConnectionClose ExpiryPolicy = "connection-close"
|
||||||
|
|
||||||
|
// The terminus never expires.
|
||||||
|
ExpiryNever ExpiryPolicy = "never"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExpiryPolicy specifies when the expiry timer of a terminus
|
||||||
|
// starts counting down from the timeout value.
|
||||||
|
//
|
||||||
|
// If the link is subsequently re-attached before the terminus is expired,
|
||||||
|
// then the count down is aborted. If the conditions for the
|
||||||
|
// terminus-expiry-policy are subsequently re-met, the expiry timer restarts
|
||||||
|
// from its originally configured timeout value.
|
||||||
|
type ExpiryPolicy Symbol
|
||||||
|
|
||||||
|
func ValidateExpiryPolicy(e ExpiryPolicy) error {
|
||||||
|
switch e {
|
||||||
|
case ExpiryLinkDetach,
|
||||||
|
ExpirySessionEnd,
|
||||||
|
ExpiryConnectionClose,
|
||||||
|
ExpiryNever:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown expiry-policy %q", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ExpiryPolicy) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Symbol(e).Marshal(wr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExpiryPolicy) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
err := Unmarshal(r, (*Symbol)(e))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ValidateExpiryPolicy(*e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExpiryPolicy) String() string {
|
||||||
|
if e == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return string(*e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sender Settlement Modes
|
||||||
|
const (
|
||||||
|
// Sender will send all deliveries initially unsettled to the receiver.
|
||||||
|
ModeUnsettled SenderSettleMode = 0
|
||||||
|
|
||||||
|
// Sender will send all deliveries settled to the receiver.
|
||||||
|
ModeSettled SenderSettleMode = 1
|
||||||
|
|
||||||
|
// Sender MAY send a mixture of settled and unsettled deliveries to the receiver.
|
||||||
|
ModeMixed SenderSettleMode = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// SenderSettleMode specifies how the sender will settle messages.
|
||||||
|
type SenderSettleMode uint8
|
||||||
|
|
||||||
|
func (m *SenderSettleMode) String() string {
|
||||||
|
if m == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *m {
|
||||||
|
case ModeUnsettled:
|
||||||
|
return "unsettled"
|
||||||
|
|
||||||
|
case ModeSettled:
|
||||||
|
return "settled"
|
||||||
|
|
||||||
|
case ModeMixed:
|
||||||
|
return "mixed"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown sender mode %d", uint8(*m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m SenderSettleMode) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Marshal(wr, uint8(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SenderSettleMode) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
n, err := ReadUbyte(r)
|
||||||
|
*m = SenderSettleMode(n)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receiver Settlement Modes
|
||||||
|
const (
|
||||||
|
// Receiver will spontaneously settle all incoming transfers.
|
||||||
|
ModeFirst ReceiverSettleMode = 0
|
||||||
|
|
||||||
|
// Receiver will only settle after sending the disposition to the
|
||||||
|
// sender and receiving a disposition indicating settlement of
|
||||||
|
// the delivery from the sender.
|
||||||
|
ModeSecond ReceiverSettleMode = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReceiverSettleMode specifies how the receiver will settle messages.
|
||||||
|
type ReceiverSettleMode uint8
|
||||||
|
|
||||||
|
func (m *ReceiverSettleMode) String() string {
|
||||||
|
if m == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *m {
|
||||||
|
case ModeFirst:
|
||||||
|
return "first"
|
||||||
|
|
||||||
|
case ModeSecond:
|
||||||
|
return "second"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown receiver mode %d", uint8(*m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ReceiverSettleMode) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Marshal(wr, uint8(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ReceiverSettleMode) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
n, err := ReadUbyte(r)
|
||||||
|
*m = ReceiverSettleMode(n)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Role bool
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleSender Role = false
|
||||||
|
RoleReceiver Role = true
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rl Role) String() string {
|
||||||
|
if rl {
|
||||||
|
return "Receiver"
|
||||||
|
}
|
||||||
|
return "Sender"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *Role) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
b, err := readBool(r)
|
||||||
|
*rl = Role(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl Role) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Marshal(wr, (bool)(rl))
|
||||||
|
}
|
||||||
|
|
||||||
|
type SASLCode uint8
|
||||||
|
|
||||||
|
// SASL Codes
|
||||||
|
const (
|
||||||
|
CodeSASLOK SASLCode = iota // Connection authentication succeeded.
|
||||||
|
CodeSASLAuth // Connection authentication failed due to an unspecified problem with the supplied credentials.
|
||||||
|
CodeSASLSysPerm // Connection authentication failed due to a system error that is unlikely to be corrected without intervention.
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s SASLCode) Marshal(wr *buffer.Buffer) error {
|
||||||
|
return Marshal(wr, uint8(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SASLCode) Unmarshal(r *buffer.Buffer) error {
|
||||||
|
n, err := ReadUbyte(r)
|
||||||
|
*s = SASLCode(n)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
type DeliveryState interface{} // TODO: http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transactions-v1.0-os.html#type-declared
|
type DeliveryState interface{} // TODO: http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transactions-v1.0-os.html#type-declared
|
||||||
|
|
||||||
type Unsettled map[string]DeliveryState
|
type Unsettled map[string]DeliveryState
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package amqp
|
package frames
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -26,7 +26,7 @@ import (
|
||||||
<field name="capabilities" type="symbol" multiple="true"/>
|
<field name="capabilities" type="symbol" multiple="true"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type source struct {
|
type Source struct {
|
||||||
// the address of the source
|
// the address of the source
|
||||||
//
|
//
|
||||||
// The address of the source MUST NOT be set when sent on a attach frame sent by
|
// The address of the source MUST NOT be set when sent on a attach frame sent by
|
||||||
|
@ -49,7 +49,7 @@ type source struct {
|
||||||
// 0: none
|
// 0: none
|
||||||
// 1: configuration
|
// 1: configuration
|
||||||
// 2: unsettled-state
|
// 2: unsettled-state
|
||||||
Durable Durability
|
Durable encoding.Durability
|
||||||
|
|
||||||
// the expiry policy of the source
|
// the expiry policy of the source
|
||||||
//
|
//
|
||||||
|
@ -59,7 +59,7 @@ type source struct {
|
||||||
// connection-close: The expiry timer starts when most recently associated connection
|
// connection-close: The expiry timer starts when most recently associated connection
|
||||||
// is closed.
|
// is closed.
|
||||||
// never: The terminus never expires.
|
// never: The terminus never expires.
|
||||||
ExpiryPolicy ExpiryPolicy
|
ExpiryPolicy encoding.ExpiryPolicy
|
||||||
|
|
||||||
// duration that an expiring source will be retained
|
// duration that an expiring source will be retained
|
||||||
//
|
//
|
||||||
|
@ -144,11 +144,11 @@ type source struct {
|
||||||
Capabilities encoding.MultiSymbol
|
Capabilities encoding.MultiSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *source) Marshal(wr *buffer.Buffer) error {
|
func (s *Source) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSource, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSource, []encoding.MarshalField{
|
||||||
{Value: &s.Address, Omit: s.Address == ""},
|
{Value: &s.Address, Omit: s.Address == ""},
|
||||||
{Value: &s.Durable, Omit: s.Durable == DurabilityNone},
|
{Value: &s.Durable, Omit: s.Durable == encoding.DurabilityNone},
|
||||||
{Value: &s.ExpiryPolicy, Omit: s.ExpiryPolicy == "" || s.ExpiryPolicy == ExpirySessionEnd},
|
{Value: &s.ExpiryPolicy, Omit: s.ExpiryPolicy == "" || s.ExpiryPolicy == encoding.ExpirySessionEnd},
|
||||||
{Value: &s.Timeout, Omit: s.Timeout == 0},
|
{Value: &s.Timeout, Omit: s.Timeout == 0},
|
||||||
{Value: &s.Dynamic, Omit: !s.Dynamic},
|
{Value: &s.Dynamic, Omit: !s.Dynamic},
|
||||||
{Value: s.DynamicNodeProperties, Omit: len(s.DynamicNodeProperties) == 0},
|
{Value: s.DynamicNodeProperties, Omit: len(s.DynamicNodeProperties) == 0},
|
||||||
|
@ -160,11 +160,11 @@ func (s *source) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *source) Unmarshal(r *buffer.Buffer) error {
|
func (s *Source) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSource, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSource, []encoding.UnmarshalField{
|
||||||
{Field: &s.Address},
|
{Field: &s.Address},
|
||||||
{Field: &s.Durable},
|
{Field: &s.Durable},
|
||||||
{Field: &s.ExpiryPolicy, HandleNull: func() error { s.ExpiryPolicy = ExpirySessionEnd; return nil }},
|
{Field: &s.ExpiryPolicy, HandleNull: func() error { s.ExpiryPolicy = encoding.ExpirySessionEnd; return nil }},
|
||||||
{Field: &s.Timeout},
|
{Field: &s.Timeout},
|
||||||
{Field: &s.Dynamic},
|
{Field: &s.Dynamic},
|
||||||
{Field: &s.DynamicNodeProperties},
|
{Field: &s.DynamicNodeProperties},
|
||||||
|
@ -176,7 +176,7 @@ func (s *source) Unmarshal(r *buffer.Buffer) error {
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s source) String() string {
|
func (s Source) String() string {
|
||||||
return fmt.Sprintf("source{Address: %s, Durable: %d, ExpiryPolicy: %s, Timeout: %d, "+
|
return fmt.Sprintf("source{Address: %s, Durable: %d, ExpiryPolicy: %s, Timeout: %d, "+
|
||||||
"Dynamic: %t, DynamicNodeProperties: %v, DistributionMode: %s, Filter: %v, DefaultOutcome: %v"+
|
"Dynamic: %t, DynamicNodeProperties: %v, DistributionMode: %s, Filter: %v, DefaultOutcome: %v"+
|
||||||
"Outcomes: %v, Capabilities: %v}",
|
"Outcomes: %v, Capabilities: %v}",
|
||||||
|
@ -206,7 +206,7 @@ func (s source) String() string {
|
||||||
<field name="capabilities" type="symbol" multiple="true"/>
|
<field name="capabilities" type="symbol" multiple="true"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type target struct {
|
type Target struct {
|
||||||
// the address of the target
|
// the address of the target
|
||||||
//
|
//
|
||||||
// The address of the target MUST NOT be set when sent on a attach frame sent by
|
// The address of the target MUST NOT be set when sent on a attach frame sent by
|
||||||
|
@ -229,7 +229,7 @@ type target struct {
|
||||||
// 0: none
|
// 0: none
|
||||||
// 1: configuration
|
// 1: configuration
|
||||||
// 2: unsettled-state
|
// 2: unsettled-state
|
||||||
Durable Durability
|
Durable encoding.Durability
|
||||||
|
|
||||||
// the expiry policy of the target
|
// the expiry policy of the target
|
||||||
//
|
//
|
||||||
|
@ -239,7 +239,7 @@ type target struct {
|
||||||
// connection-close: The expiry timer starts when most recently associated connection
|
// connection-close: The expiry timer starts when most recently associated connection
|
||||||
// is closed.
|
// is closed.
|
||||||
// never: The terminus never expires.
|
// never: The terminus never expires.
|
||||||
ExpiryPolicy ExpiryPolicy
|
ExpiryPolicy encoding.ExpiryPolicy
|
||||||
|
|
||||||
// duration that an expiring target will be retained
|
// duration that an expiring target will be retained
|
||||||
//
|
//
|
||||||
|
@ -291,11 +291,11 @@ type target struct {
|
||||||
Capabilities encoding.MultiSymbol
|
Capabilities encoding.MultiSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) Marshal(wr *buffer.Buffer) error {
|
func (t *Target) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeTarget, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeTarget, []encoding.MarshalField{
|
||||||
{Value: &t.Address, Omit: t.Address == ""},
|
{Value: &t.Address, Omit: t.Address == ""},
|
||||||
{Value: &t.Durable, Omit: t.Durable == DurabilityNone},
|
{Value: &t.Durable, Omit: t.Durable == encoding.DurabilityNone},
|
||||||
{Value: &t.ExpiryPolicy, Omit: t.ExpiryPolicy == "" || t.ExpiryPolicy == ExpirySessionEnd},
|
{Value: &t.ExpiryPolicy, Omit: t.ExpiryPolicy == "" || t.ExpiryPolicy == encoding.ExpirySessionEnd},
|
||||||
{Value: &t.Timeout, Omit: t.Timeout == 0},
|
{Value: &t.Timeout, Omit: t.Timeout == 0},
|
||||||
{Value: &t.Dynamic, Omit: !t.Dynamic},
|
{Value: &t.Dynamic, Omit: !t.Dynamic},
|
||||||
{Value: t.DynamicNodeProperties, Omit: len(t.DynamicNodeProperties) == 0},
|
{Value: t.DynamicNodeProperties, Omit: len(t.DynamicNodeProperties) == 0},
|
||||||
|
@ -303,11 +303,11 @@ func (t *target) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) Unmarshal(r *buffer.Buffer) error {
|
func (t *Target) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeTarget, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeTarget, []encoding.UnmarshalField{
|
||||||
{Field: &t.Address},
|
{Field: &t.Address},
|
||||||
{Field: &t.Durable},
|
{Field: &t.Durable},
|
||||||
{Field: &t.ExpiryPolicy, HandleNull: func() error { t.ExpiryPolicy = ExpirySessionEnd; return nil }},
|
{Field: &t.ExpiryPolicy, HandleNull: func() error { t.ExpiryPolicy = encoding.ExpirySessionEnd; return nil }},
|
||||||
{Field: &t.Timeout},
|
{Field: &t.Timeout},
|
||||||
{Field: &t.Dynamic},
|
{Field: &t.Dynamic},
|
||||||
{Field: &t.DynamicNodeProperties},
|
{Field: &t.DynamicNodeProperties},
|
||||||
|
@ -315,7 +315,7 @@ func (t *target) Unmarshal(r *buffer.Buffer) error {
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t target) String() string {
|
func (t Target) String() string {
|
||||||
return fmt.Sprintf("source{Address: %s, Durable: %d, ExpiryPolicy: %s, Timeout: %d, "+
|
return fmt.Sprintf("source{Address: %s, Durable: %d, ExpiryPolicy: %s, Timeout: %d, "+
|
||||||
"Dynamic: %t, DynamicNodeProperties: %v, Capabilities: %v}",
|
"Dynamic: %t, DynamicNodeProperties: %v, Capabilities: %v}",
|
||||||
t.Address,
|
t.Address,
|
||||||
|
@ -329,17 +329,17 @@ func (t target) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// frame is the decoded representation of a frame
|
// frame is the decoded representation of a frame
|
||||||
type frame struct {
|
type Frame struct {
|
||||||
type_ uint8 // AMQP/SASL
|
Type uint8 // AMQP/SASL
|
||||||
channel uint16 // channel this frame is for
|
Channel uint16 // channel this frame is for
|
||||||
body frameBody // body of the frame
|
Body FrameBody // body of the frame
|
||||||
|
|
||||||
// optional channel which will be closed after net transmit
|
// optional channel which will be closed after net transmit
|
||||||
done chan encoding.DeliveryState
|
Done chan encoding.DeliveryState
|
||||||
}
|
}
|
||||||
|
|
||||||
// frameBody adds some type safety to frame encoding
|
// frameBody adds some type safety to frame encoding
|
||||||
type frameBody interface {
|
type FrameBody interface {
|
||||||
frameBody()
|
frameBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ type frameBody interface {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type performOpen struct {
|
type PerformOpen struct {
|
||||||
ContainerID string // required
|
ContainerID string // required
|
||||||
Hostname string
|
Hostname string
|
||||||
MaxFrameSize uint32 // default: 4294967295
|
MaxFrameSize uint32 // default: 4294967295
|
||||||
|
@ -372,9 +372,9 @@ type performOpen struct {
|
||||||
Properties map[encoding.Symbol]interface{}
|
Properties map[encoding.Symbol]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *performOpen) frameBody() {}
|
func (o *PerformOpen) frameBody() {}
|
||||||
|
|
||||||
func (o *performOpen) Marshal(wr *buffer.Buffer) error {
|
func (o *PerformOpen) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeOpen, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeOpen, []encoding.MarshalField{
|
||||||
{Value: &o.ContainerID, Omit: false},
|
{Value: &o.ContainerID, Omit: false},
|
||||||
{Value: &o.Hostname, Omit: o.Hostname == ""},
|
{Value: &o.Hostname, Omit: o.Hostname == ""},
|
||||||
|
@ -389,7 +389,7 @@ func (o *performOpen) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *performOpen) Unmarshal(r *buffer.Buffer) error {
|
func (o *PerformOpen) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeOpen, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeOpen, []encoding.UnmarshalField{
|
||||||
{Field: &o.ContainerID, HandleNull: func() error { return errors.New("Open.ContainerID is required") }},
|
{Field: &o.ContainerID, HandleNull: func() error { return errors.New("Open.ContainerID is required") }},
|
||||||
{Field: &o.Hostname},
|
{Field: &o.Hostname},
|
||||||
|
@ -404,7 +404,7 @@ func (o *performOpen) Unmarshal(r *buffer.Buffer) error {
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *performOpen) String() string {
|
func (o *PerformOpen) String() string {
|
||||||
return fmt.Sprintf("Open{ContainerID : %s, Hostname: %s, MaxFrameSize: %d, "+
|
return fmt.Sprintf("Open{ContainerID : %s, Hostname: %s, MaxFrameSize: %d, "+
|
||||||
"ChannelMax: %d, IdleTimeout: %v, "+
|
"ChannelMax: %d, IdleTimeout: %v, "+
|
||||||
"OutgoingLocales: %v, IncomingLocales: %v, "+
|
"OutgoingLocales: %v, IncomingLocales: %v, "+
|
||||||
|
@ -436,7 +436,7 @@ func (o *performOpen) String() string {
|
||||||
<field name="properties" type="fields"/>
|
<field name="properties" type="fields"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performBegin struct {
|
type PerformBegin struct {
|
||||||
// the remote channel for this session
|
// the remote channel for this session
|
||||||
// If a session is locally initiated, the remote-channel MUST NOT be set.
|
// If a session is locally initiated, the remote-channel MUST NOT be set.
|
||||||
// When an endpoint responds to a remotely initiated session, the remote-channel
|
// When an endpoint responds to a remotely initiated session, the remote-channel
|
||||||
|
@ -474,9 +474,9 @@ type performBegin struct {
|
||||||
Properties map[encoding.Symbol]interface{}
|
Properties map[encoding.Symbol]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *performBegin) frameBody() {}
|
func (b *PerformBegin) frameBody() {}
|
||||||
|
|
||||||
func (b *performBegin) String() string {
|
func (b *PerformBegin) String() string {
|
||||||
return fmt.Sprintf("Begin{RemoteChannel: %v, NextOutgoingID: %d, IncomingWindow: %d, "+
|
return fmt.Sprintf("Begin{RemoteChannel: %v, NextOutgoingID: %d, IncomingWindow: %d, "+
|
||||||
"OutgoingWindow: %d, HandleMax: %d, OfferedCapabilities: %v, DesiredCapabilities: %v, "+
|
"OutgoingWindow: %d, HandleMax: %d, OfferedCapabilities: %v, DesiredCapabilities: %v, "+
|
||||||
"Properties: %v}",
|
"Properties: %v}",
|
||||||
|
@ -498,7 +498,7 @@ func formatUint16Ptr(p *uint16) string {
|
||||||
return strconv.FormatUint(uint64(*p), 10)
|
return strconv.FormatUint(uint64(*p), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *performBegin) Marshal(wr *buffer.Buffer) error {
|
func (b *PerformBegin) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeBegin, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeBegin, []encoding.MarshalField{
|
||||||
{Value: b.RemoteChannel, Omit: b.RemoteChannel == nil},
|
{Value: b.RemoteChannel, Omit: b.RemoteChannel == nil},
|
||||||
{Value: &b.NextOutgoingID, Omit: false},
|
{Value: &b.NextOutgoingID, Omit: false},
|
||||||
|
@ -511,7 +511,7 @@ func (b *performBegin) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *performBegin) Unmarshal(r *buffer.Buffer) error {
|
func (b *PerformBegin) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeBegin, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeBegin, []encoding.UnmarshalField{
|
||||||
{Field: &b.RemoteChannel},
|
{Field: &b.RemoteChannel},
|
||||||
{Field: &b.NextOutgoingID, HandleNull: func() error { return errors.New("Begin.NextOutgoingID is required") }},
|
{Field: &b.NextOutgoingID, HandleNull: func() error { return errors.New("Begin.NextOutgoingID is required") }},
|
||||||
|
@ -543,7 +543,7 @@ func (b *performBegin) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="properties" type="fields"/>
|
<field name="properties" type="fields"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performAttach struct {
|
type PerformAttach struct {
|
||||||
// the name of the link
|
// the name of the link
|
||||||
//
|
//
|
||||||
// This name uniquely identifies the link from the container of the source
|
// This name uniquely identifies the link from the container of the source
|
||||||
|
@ -572,7 +572,7 @@ type performAttach struct {
|
||||||
//
|
//
|
||||||
// The role being played by the peer, i.e., whether the peer is the sender or the
|
// The role being played by the peer, i.e., whether the peer is the sender or the
|
||||||
// receiver of messages on the link.
|
// receiver of messages on the link.
|
||||||
Role role
|
Role encoding.Role
|
||||||
|
|
||||||
// settlement policy for the sender
|
// settlement policy for the sender
|
||||||
//
|
//
|
||||||
|
@ -585,7 +585,7 @@ type performAttach struct {
|
||||||
// 0: unsettled - The sender will send all deliveries initially unsettled to the receiver.
|
// 0: unsettled - The sender will send all deliveries initially unsettled to the receiver.
|
||||||
// 1: settled - The sender will send all deliveries settled to the receiver.
|
// 1: settled - The sender will send all deliveries settled to the receiver.
|
||||||
// 2: mixed - The sender MAY send a mixture of settled and unsettled deliveries to the receiver.
|
// 2: mixed - The sender MAY send a mixture of settled and unsettled deliveries to the receiver.
|
||||||
SenderSettleMode *SenderSettleMode
|
SenderSettleMode *encoding.SenderSettleMode
|
||||||
|
|
||||||
// the settlement policy of the receiver
|
// the settlement policy of the receiver
|
||||||
//
|
//
|
||||||
|
@ -599,19 +599,19 @@ type performAttach struct {
|
||||||
// 1: second - The receiver will only settle after sending the disposition to
|
// 1: second - The receiver will only settle after sending the disposition to
|
||||||
// the sender and receiving a disposition indicating settlement of
|
// the sender and receiving a disposition indicating settlement of
|
||||||
// the delivery from the sender.
|
// the delivery from the sender.
|
||||||
ReceiverSettleMode *ReceiverSettleMode
|
ReceiverSettleMode *encoding.ReceiverSettleMode
|
||||||
|
|
||||||
// the source for messages
|
// the source for messages
|
||||||
//
|
//
|
||||||
// If no source is specified on an outgoing link, then there is no source currently
|
// If no source is specified on an outgoing link, then there is no source currently
|
||||||
// attached to the link. A link with no source will never produce outgoing messages.
|
// attached to the link. A link with no source will never produce outgoing messages.
|
||||||
Source *source
|
Source *Source
|
||||||
|
|
||||||
// the target for messages
|
// the target for messages
|
||||||
//
|
//
|
||||||
// If no target is specified on an incoming link, then there is no target currently
|
// If no target is specified on an incoming link, then there is no target currently
|
||||||
// attached to the link. A link with no target will never permit incoming messages.
|
// attached to the link. A link with no target will never permit incoming messages.
|
||||||
Target *target
|
Target *Target
|
||||||
|
|
||||||
// unsettled delivery state
|
// unsettled delivery state
|
||||||
//
|
//
|
||||||
|
@ -674,9 +674,9 @@ type performAttach struct {
|
||||||
Properties map[encoding.Symbol]interface{}
|
Properties map[encoding.Symbol]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *performAttach) frameBody() {}
|
func (a *PerformAttach) frameBody() {}
|
||||||
|
|
||||||
func (a performAttach) String() string {
|
func (a PerformAttach) String() string {
|
||||||
return fmt.Sprintf("Attach{Name: %s, Handle: %d, Role: %s, SenderSettleMode: %s, ReceiverSettleMode: %s, "+
|
return fmt.Sprintf("Attach{Name: %s, Handle: %d, Role: %s, SenderSettleMode: %s, ReceiverSettleMode: %s, "+
|
||||||
"Source: %v, Target: %v, Unsettled: %v, IncompleteUnsettled: %t, InitialDeliveryCount: %d, MaxMessageSize: %d, "+
|
"Source: %v, Target: %v, Unsettled: %v, IncompleteUnsettled: %t, InitialDeliveryCount: %d, MaxMessageSize: %d, "+
|
||||||
"OfferedCapabilities: %v, DesiredCapabilities: %v, Properties: %v}",
|
"OfferedCapabilities: %v, DesiredCapabilities: %v, Properties: %v}",
|
||||||
|
@ -697,7 +697,7 @@ func (a performAttach) String() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *performAttach) Marshal(wr *buffer.Buffer) error {
|
func (a *PerformAttach) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeAttach, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeAttach, []encoding.MarshalField{
|
||||||
{Value: &a.Name, Omit: false},
|
{Value: &a.Name, Omit: false},
|
||||||
{Value: &a.Handle, Omit: false},
|
{Value: &a.Handle, Omit: false},
|
||||||
|
@ -708,7 +708,7 @@ func (a *performAttach) Marshal(wr *buffer.Buffer) error {
|
||||||
{Value: a.Target, Omit: a.Target == nil},
|
{Value: a.Target, Omit: a.Target == nil},
|
||||||
{Value: a.Unsettled, Omit: len(a.Unsettled) == 0},
|
{Value: a.Unsettled, Omit: len(a.Unsettled) == 0},
|
||||||
{Value: &a.IncompleteUnsettled, Omit: !a.IncompleteUnsettled},
|
{Value: &a.IncompleteUnsettled, Omit: !a.IncompleteUnsettled},
|
||||||
{Value: &a.InitialDeliveryCount, Omit: a.Role == roleReceiver},
|
{Value: &a.InitialDeliveryCount, Omit: a.Role == encoding.RoleReceiver},
|
||||||
{Value: &a.MaxMessageSize, Omit: a.MaxMessageSize == 0},
|
{Value: &a.MaxMessageSize, Omit: a.MaxMessageSize == 0},
|
||||||
{Value: &a.OfferedCapabilities, Omit: len(a.OfferedCapabilities) == 0},
|
{Value: &a.OfferedCapabilities, Omit: len(a.OfferedCapabilities) == 0},
|
||||||
{Value: &a.DesiredCapabilities, Omit: len(a.DesiredCapabilities) == 0},
|
{Value: &a.DesiredCapabilities, Omit: len(a.DesiredCapabilities) == 0},
|
||||||
|
@ -716,7 +716,7 @@ func (a *performAttach) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *performAttach) Unmarshal(r *buffer.Buffer) error {
|
func (a *PerformAttach) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeAttach, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeAttach, []encoding.UnmarshalField{
|
||||||
{Field: &a.Name, HandleNull: func() error { return errors.New("Attach.Name is required") }},
|
{Field: &a.Name, HandleNull: func() error { return errors.New("Attach.Name is required") }},
|
||||||
{Field: &a.Handle, HandleNull: func() error { return errors.New("Attach.Handle is required") }},
|
{Field: &a.Handle, HandleNull: func() error { return errors.New("Attach.Handle is required") }},
|
||||||
|
@ -751,7 +751,7 @@ func (a *performAttach) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="properties" type="fields"/>
|
<field name="properties" type="fields"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performFlow struct {
|
type PerformFlow struct {
|
||||||
// Identifies the expected transfer-id of the next incoming transfer frame.
|
// Identifies the expected transfer-id of the next incoming transfer frame.
|
||||||
// This value MUST be set if the peer has received the begin frame for the
|
// This value MUST be set if the peer has received the begin frame for the
|
||||||
// session, and MUST NOT be set if it has not. See subsection 2.5.6 for more details.
|
// session, and MUST NOT be set if it has not. See subsection 2.5.6 for more details.
|
||||||
|
@ -850,9 +850,9 @@ type performFlow struct {
|
||||||
Properties map[encoding.Symbol]interface{}
|
Properties map[encoding.Symbol]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *performFlow) frameBody() {}
|
func (f *PerformFlow) frameBody() {}
|
||||||
|
|
||||||
func (f *performFlow) String() string {
|
func (f *PerformFlow) String() string {
|
||||||
return fmt.Sprintf("Flow{NextIncomingID: %s, IncomingWindow: %d, NextOutgoingID: %d, OutgoingWindow: %d, "+
|
return fmt.Sprintf("Flow{NextIncomingID: %s, IncomingWindow: %d, NextOutgoingID: %d, OutgoingWindow: %d, "+
|
||||||
"Handle: %s, DeliveryCount: %s, LinkCredit: %s, Available: %s, Drain: %t, Echo: %t, Properties: %+v}",
|
"Handle: %s, DeliveryCount: %s, LinkCredit: %s, Available: %s, Drain: %t, Echo: %t, Properties: %+v}",
|
||||||
formatUint32Ptr(f.NextIncomingID),
|
formatUint32Ptr(f.NextIncomingID),
|
||||||
|
@ -876,7 +876,7 @@ func formatUint32Ptr(p *uint32) string {
|
||||||
return strconv.FormatUint(uint64(*p), 10)
|
return strconv.FormatUint(uint64(*p), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *performFlow) Marshal(wr *buffer.Buffer) error {
|
func (f *PerformFlow) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeFlow, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeFlow, []encoding.MarshalField{
|
||||||
{Value: f.NextIncomingID, Omit: f.NextIncomingID == nil},
|
{Value: f.NextIncomingID, Omit: f.NextIncomingID == nil},
|
||||||
{Value: &f.IncomingWindow, Omit: false},
|
{Value: &f.IncomingWindow, Omit: false},
|
||||||
|
@ -892,7 +892,7 @@ func (f *performFlow) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *performFlow) Unmarshal(r *buffer.Buffer) error {
|
func (f *PerformFlow) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeFlow, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeFlow, []encoding.UnmarshalField{
|
||||||
{Field: &f.NextIncomingID},
|
{Field: &f.NextIncomingID},
|
||||||
{Field: &f.IncomingWindow, HandleNull: func() error { return errors.New("Flow.IncomingWindow is required") }},
|
{Field: &f.IncomingWindow, HandleNull: func() error { return errors.New("Flow.IncomingWindow is required") }},
|
||||||
|
@ -924,7 +924,7 @@ func (f *performFlow) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="batchable" type="boolean" default="false"/>
|
<field name="batchable" type="boolean" default="false"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performTransfer struct {
|
type PerformTransfer struct {
|
||||||
// Specifies the link on which the message is transferred.
|
// Specifies the link on which the message is transferred.
|
||||||
Handle uint32 // required
|
Handle uint32 // required
|
||||||
|
|
||||||
|
@ -997,7 +997,7 @@ type performTransfer struct {
|
||||||
// 1: second - The receiver will only settle after sending the disposition to
|
// 1: second - The receiver will only settle after sending the disposition to
|
||||||
// the sender and receiving a disposition indicating settlement of
|
// the sender and receiving a disposition indicating settlement of
|
||||||
// the delivery from the sender.
|
// the delivery from the sender.
|
||||||
ReceiverSettleMode *ReceiverSettleMode
|
ReceiverSettleMode *encoding.ReceiverSettleMode
|
||||||
|
|
||||||
// the state of the delivery at the sender
|
// the state of the delivery at the sender
|
||||||
//
|
//
|
||||||
|
@ -1065,12 +1065,12 @@ type performTransfer struct {
|
||||||
//
|
//
|
||||||
// Settled=true: closed when the transferred on network.
|
// Settled=true: closed when the transferred on network.
|
||||||
// Settled=false: closed when the receiver has confirmed settlement.
|
// Settled=false: closed when the receiver has confirmed settlement.
|
||||||
done chan encoding.DeliveryState
|
Done chan encoding.DeliveryState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *performTransfer) frameBody() {}
|
func (t *PerformTransfer) frameBody() {}
|
||||||
|
|
||||||
func (t performTransfer) String() string {
|
func (t PerformTransfer) String() string {
|
||||||
deliveryTag := "<nil>"
|
deliveryTag := "<nil>"
|
||||||
if t.DeliveryTag != nil {
|
if t.DeliveryTag != nil {
|
||||||
deliveryTag = fmt.Sprintf("%q", t.DeliveryTag)
|
deliveryTag = fmt.Sprintf("%q", t.DeliveryTag)
|
||||||
|
@ -1094,7 +1094,7 @@ func (t performTransfer) String() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *performTransfer) Marshal(wr *buffer.Buffer) error {
|
func (t *PerformTransfer) Marshal(wr *buffer.Buffer) error {
|
||||||
err := encoding.MarshalComposite(wr, encoding.TypeCodeTransfer, []encoding.MarshalField{
|
err := encoding.MarshalComposite(wr, encoding.TypeCodeTransfer, []encoding.MarshalField{
|
||||||
{Value: &t.Handle},
|
{Value: &t.Handle},
|
||||||
{Value: t.DeliveryID, Omit: t.DeliveryID == nil},
|
{Value: t.DeliveryID, Omit: t.DeliveryID == nil},
|
||||||
|
@ -1116,7 +1116,7 @@ func (t *performTransfer) Marshal(wr *buffer.Buffer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *performTransfer) Unmarshal(r *buffer.Buffer) error {
|
func (t *PerformTransfer) Unmarshal(r *buffer.Buffer) error {
|
||||||
err := encoding.UnmarshalComposite(r, encoding.TypeCodeTransfer, []encoding.UnmarshalField{
|
err := encoding.UnmarshalComposite(r, encoding.TypeCodeTransfer, []encoding.UnmarshalField{
|
||||||
{Field: &t.Handle, HandleNull: func() error { return errors.New("Transfer.Handle is required") }},
|
{Field: &t.Handle, HandleNull: func() error { return errors.New("Transfer.Handle is required") }},
|
||||||
{Field: &t.DeliveryID},
|
{Field: &t.DeliveryID},
|
||||||
|
@ -1150,12 +1150,12 @@ func (t *performTransfer) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="batchable" type="boolean" default="false"/>
|
<field name="batchable" type="boolean" default="false"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performDisposition struct {
|
type PerformDisposition struct {
|
||||||
// directionality of disposition
|
// directionality of disposition
|
||||||
//
|
//
|
||||||
// The role identifies whether the disposition frame contains information about
|
// The role identifies whether the disposition frame contains information about
|
||||||
// sending link endpoints or receiving link endpoints.
|
// sending link endpoints or receiving link endpoints.
|
||||||
Role role
|
Role encoding.Role
|
||||||
|
|
||||||
// lower bound of deliveries
|
// lower bound of deliveries
|
||||||
//
|
//
|
||||||
|
@ -1188,9 +1188,9 @@ type performDisposition struct {
|
||||||
Batchable bool
|
Batchable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDisposition) frameBody() {}
|
func (d *PerformDisposition) frameBody() {}
|
||||||
|
|
||||||
func (d performDisposition) String() string {
|
func (d PerformDisposition) String() string {
|
||||||
return fmt.Sprintf("Disposition{Role: %s, First: %d, Last: %s, Settled: %t, State: %s, Batchable: %t}",
|
return fmt.Sprintf("Disposition{Role: %s, First: %d, Last: %s, Settled: %t, State: %s, Batchable: %t}",
|
||||||
d.Role,
|
d.Role,
|
||||||
d.First,
|
d.First,
|
||||||
|
@ -1201,7 +1201,7 @@ func (d performDisposition) String() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDisposition) Marshal(wr *buffer.Buffer) error {
|
func (d *PerformDisposition) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeDisposition, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeDisposition, []encoding.MarshalField{
|
||||||
{Value: &d.Role, Omit: false},
|
{Value: &d.Role, Omit: false},
|
||||||
{Value: &d.First, Omit: false},
|
{Value: &d.First, Omit: false},
|
||||||
|
@ -1212,7 +1212,7 @@ func (d *performDisposition) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDisposition) Unmarshal(r *buffer.Buffer) error {
|
func (d *PerformDisposition) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeDisposition, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeDisposition, []encoding.UnmarshalField{
|
||||||
{Field: &d.Role, HandleNull: func() error { return errors.New("Disposition.Role is required") }},
|
{Field: &d.Role, HandleNull: func() error { return errors.New("Disposition.Role is required") }},
|
||||||
{Field: &d.First, HandleNull: func() error { return errors.New("Disposition.Handle is required") }},
|
{Field: &d.First, HandleNull: func() error { return errors.New("Disposition.Handle is required") }},
|
||||||
|
@ -1231,7 +1231,7 @@ func (d *performDisposition) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="error" type="error"/>
|
<field name="error" type="error"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performDetach struct {
|
type PerformDetach struct {
|
||||||
// the local handle of the link to be detached
|
// the local handle of the link to be detached
|
||||||
Handle uint32 //required
|
Handle uint32 //required
|
||||||
|
|
||||||
|
@ -1242,12 +1242,12 @@ type performDetach struct {
|
||||||
//
|
//
|
||||||
// If set, this field indicates that the link is being detached due to an error
|
// If set, this field indicates that the link is being detached due to an error
|
||||||
// condition. The value of the field SHOULD contain details on the cause of the error.
|
// condition. The value of the field SHOULD contain details on the cause of the error.
|
||||||
Error *Error
|
Error *encoding.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDetach) frameBody() {}
|
func (d *PerformDetach) frameBody() {}
|
||||||
|
|
||||||
func (d performDetach) String() string {
|
func (d PerformDetach) String() string {
|
||||||
return fmt.Sprintf("Detach{Handle: %d, Closed: %t, Error: %v}",
|
return fmt.Sprintf("Detach{Handle: %d, Closed: %t, Error: %v}",
|
||||||
d.Handle,
|
d.Handle,
|
||||||
d.Closed,
|
d.Closed,
|
||||||
|
@ -1255,7 +1255,7 @@ func (d performDetach) String() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDetach) Marshal(wr *buffer.Buffer) error {
|
func (d *PerformDetach) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeDetach, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeDetach, []encoding.MarshalField{
|
||||||
{Value: &d.Handle, Omit: false},
|
{Value: &d.Handle, Omit: false},
|
||||||
{Value: &d.Closed, Omit: !d.Closed},
|
{Value: &d.Closed, Omit: !d.Closed},
|
||||||
|
@ -1263,7 +1263,7 @@ func (d *performDetach) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *performDetach) Unmarshal(r *buffer.Buffer) error {
|
func (d *PerformDetach) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeDetach, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeDetach, []encoding.UnmarshalField{
|
||||||
{Field: &d.Handle, HandleNull: func() error { return errors.New("Detach.Handle is required") }},
|
{Field: &d.Handle, HandleNull: func() error { return errors.New("Detach.Handle is required") }},
|
||||||
{Field: &d.Closed},
|
{Field: &d.Closed},
|
||||||
|
@ -1277,23 +1277,23 @@ func (d *performDetach) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="error" type="error"/>
|
<field name="error" type="error"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performEnd struct {
|
type PerformEnd struct {
|
||||||
// error causing the end
|
// error causing the end
|
||||||
//
|
//
|
||||||
// If set, this field indicates that the session is being ended due to an error
|
// If set, this field indicates that the session is being ended due to an error
|
||||||
// condition. The value of the field SHOULD contain details on the cause of the error.
|
// condition. The value of the field SHOULD contain details on the cause of the error.
|
||||||
Error *Error
|
Error *encoding.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *performEnd) frameBody() {}
|
func (e *PerformEnd) frameBody() {}
|
||||||
|
|
||||||
func (e *performEnd) Marshal(wr *buffer.Buffer) error {
|
func (e *PerformEnd) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeEnd, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeEnd, []encoding.MarshalField{
|
||||||
{Value: e.Error, Omit: e.Error == nil},
|
{Value: e.Error, Omit: e.Error == nil},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *performEnd) Unmarshal(r *buffer.Buffer) error {
|
func (e *PerformEnd) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeEnd,
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeEnd,
|
||||||
encoding.UnmarshalField{Field: &e.Error},
|
encoding.UnmarshalField{Field: &e.Error},
|
||||||
)
|
)
|
||||||
|
@ -1305,29 +1305,29 @@ func (e *performEnd) Unmarshal(r *buffer.Buffer) error {
|
||||||
<field name="error" type="error"/>
|
<field name="error" type="error"/>
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
type performClose struct {
|
type PerformClose struct {
|
||||||
// error causing the close
|
// error causing the close
|
||||||
//
|
//
|
||||||
// If set, this field indicates that the session is being closed due to an error
|
// If set, this field indicates that the session is being closed due to an error
|
||||||
// condition. The value of the field SHOULD contain details on the cause of the error.
|
// condition. The value of the field SHOULD contain details on the cause of the error.
|
||||||
Error *Error
|
Error *encoding.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *performClose) frameBody() {}
|
func (c *PerformClose) frameBody() {}
|
||||||
|
|
||||||
func (c *performClose) Marshal(wr *buffer.Buffer) error {
|
func (c *PerformClose) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeClose, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeClose, []encoding.MarshalField{
|
||||||
{Value: c.Error, Omit: c.Error == nil},
|
{Value: c.Error, Omit: c.Error == nil},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *performClose) Unmarshal(r *buffer.Buffer) error {
|
func (c *PerformClose) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeClose,
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeClose,
|
||||||
encoding.UnmarshalField{Field: &c.Error},
|
encoding.UnmarshalField{Field: &c.Error},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *performClose) String() string {
|
func (c *PerformClose) String() string {
|
||||||
return fmt.Sprintf("Close{Error: %s}", c.Error)
|
return fmt.Sprintf("Close{Error: %s}", c.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,15 +1340,15 @@ func (c *performClose) String() string {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type saslInit struct {
|
type SASLInit struct {
|
||||||
Mechanism encoding.Symbol
|
Mechanism encoding.Symbol
|
||||||
InitialResponse []byte
|
InitialResponse []byte
|
||||||
Hostname string
|
Hostname string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (si *saslInit) frameBody() {}
|
func (si *SASLInit) frameBody() {}
|
||||||
|
|
||||||
func (si *saslInit) Marshal(wr *buffer.Buffer) error {
|
func (si *SASLInit) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLInit, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLInit, []encoding.MarshalField{
|
||||||
{Value: &si.Mechanism, Omit: false},
|
{Value: &si.Mechanism, Omit: false},
|
||||||
{Value: &si.InitialResponse, Omit: len(si.InitialResponse) == 0},
|
{Value: &si.InitialResponse, Omit: len(si.InitialResponse) == 0},
|
||||||
|
@ -1356,7 +1356,7 @@ func (si *saslInit) Marshal(wr *buffer.Buffer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (si *saslInit) Unmarshal(r *buffer.Buffer) error {
|
func (si *SASLInit) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLInit, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLInit, []encoding.UnmarshalField{
|
||||||
{Field: &si.Mechanism, HandleNull: func() error { return errors.New("saslInit.Mechanism is required") }},
|
{Field: &si.Mechanism, HandleNull: func() error { return errors.New("saslInit.Mechanism is required") }},
|
||||||
{Field: &si.InitialResponse},
|
{Field: &si.InitialResponse},
|
||||||
|
@ -1364,7 +1364,7 @@ func (si *saslInit) Unmarshal(r *buffer.Buffer) error {
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (si *saslInit) String() string {
|
func (si *SASLInit) String() string {
|
||||||
// Elide the InitialResponse as it may contain a plain text secret.
|
// Elide the InitialResponse as it may contain a plain text secret.
|
||||||
return fmt.Sprintf("SaslInit{Mechanism : %s, InitialResponse: ********, Hostname: %s}",
|
return fmt.Sprintf("SaslInit{Mechanism : %s, InitialResponse: ********, Hostname: %s}",
|
||||||
si.Mechanism,
|
si.Mechanism,
|
||||||
|
@ -1379,25 +1379,25 @@ func (si *saslInit) String() string {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type saslMechanisms struct {
|
type SASLMechanisms struct {
|
||||||
Mechanisms encoding.MultiSymbol
|
Mechanisms encoding.MultiSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *saslMechanisms) frameBody() {}
|
func (sm *SASLMechanisms) frameBody() {}
|
||||||
|
|
||||||
func (sm *saslMechanisms) Marshal(wr *buffer.Buffer) error {
|
func (sm *SASLMechanisms) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLMechanism, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLMechanism, []encoding.MarshalField{
|
||||||
{Value: &sm.Mechanisms, Omit: false},
|
{Value: &sm.Mechanisms, Omit: false},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *saslMechanisms) Unmarshal(r *buffer.Buffer) error {
|
func (sm *SASLMechanisms) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLMechanism,
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLMechanism,
|
||||||
encoding.UnmarshalField{Field: &sm.Mechanisms, HandleNull: func() error { return errors.New("saslMechanisms.Mechanisms is required") }},
|
encoding.UnmarshalField{Field: &sm.Mechanisms, HandleNull: func() error { return errors.New("saslMechanisms.Mechanisms is required") }},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *saslMechanisms) String() string {
|
func (sm *SASLMechanisms) String() string {
|
||||||
return fmt.Sprintf("SaslMechanisms{Mechanisms : %v}",
|
return fmt.Sprintf("SaslMechanisms{Mechanisms : %v}",
|
||||||
sm.Mechanisms,
|
sm.Mechanisms,
|
||||||
)
|
)
|
||||||
|
@ -1410,23 +1410,23 @@ func (sm *saslMechanisms) String() string {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type saslChallenge struct {
|
type SASLChallenge struct {
|
||||||
Challenge []byte
|
Challenge []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *saslChallenge) String() string {
|
func (sc *SASLChallenge) String() string {
|
||||||
return "Challenge{Challenge: ********}"
|
return "Challenge{Challenge: ********}"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *saslChallenge) frameBody() {}
|
func (sc *SASLChallenge) frameBody() {}
|
||||||
|
|
||||||
func (sc *saslChallenge) Marshal(wr *buffer.Buffer) error {
|
func (sc *SASLChallenge) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLChallenge, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLChallenge, []encoding.MarshalField{
|
||||||
{Value: &sc.Challenge, Omit: false},
|
{Value: &sc.Challenge, Omit: false},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *saslChallenge) Unmarshal(r *buffer.Buffer) error {
|
func (sc *SASLChallenge) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLChallenge, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLChallenge, []encoding.UnmarshalField{
|
||||||
{Field: &sc.Challenge, HandleNull: func() error { return errors.New("saslChallenge.Challenge is required") }},
|
{Field: &sc.Challenge, HandleNull: func() error { return errors.New("saslChallenge.Challenge is required") }},
|
||||||
}...)
|
}...)
|
||||||
|
@ -1439,23 +1439,23 @@ func (sc *saslChallenge) Unmarshal(r *buffer.Buffer) error {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type saslResponse struct {
|
type SASLResponse struct {
|
||||||
Response []byte
|
Response []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *saslResponse) String() string {
|
func (sr *SASLResponse) String() string {
|
||||||
return "Response{Response: ********}"
|
return "Response{Response: ********}"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *saslResponse) frameBody() {}
|
func (sr *SASLResponse) frameBody() {}
|
||||||
|
|
||||||
func (sr *saslResponse) Marshal(wr *buffer.Buffer) error {
|
func (sr *SASLResponse) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLResponse, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLResponse, []encoding.MarshalField{
|
||||||
{Value: &sr.Response, Omit: false},
|
{Value: &sr.Response, Omit: false},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *saslResponse) Unmarshal(r *buffer.Buffer) error {
|
func (sr *SASLResponse) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLResponse, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLResponse, []encoding.UnmarshalField{
|
||||||
{Field: &sr.Response, HandleNull: func() error { return errors.New("saslResponse.Response is required") }},
|
{Field: &sr.Response, HandleNull: func() error { return errors.New("saslResponse.Response is required") }},
|
||||||
}...)
|
}...)
|
||||||
|
@ -1469,28 +1469,28 @@ func (sr *saslResponse) Unmarshal(r *buffer.Buffer) error {
|
||||||
</type>
|
</type>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type saslOutcome struct {
|
type SASLOutcome struct {
|
||||||
Code saslCode
|
Code encoding.SASLCode
|
||||||
AdditionalData []byte
|
AdditionalData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *saslOutcome) frameBody() {}
|
func (so *SASLOutcome) frameBody() {}
|
||||||
|
|
||||||
func (so *saslOutcome) Marshal(wr *buffer.Buffer) error {
|
func (so *SASLOutcome) Marshal(wr *buffer.Buffer) error {
|
||||||
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLOutcome, []encoding.MarshalField{
|
return encoding.MarshalComposite(wr, encoding.TypeCodeSASLOutcome, []encoding.MarshalField{
|
||||||
{Value: &so.Code, Omit: false},
|
{Value: &so.Code, Omit: false},
|
||||||
{Value: &so.AdditionalData, Omit: len(so.AdditionalData) == 0},
|
{Value: &so.AdditionalData, Omit: len(so.AdditionalData) == 0},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *saslOutcome) Unmarshal(r *buffer.Buffer) error {
|
func (so *SASLOutcome) Unmarshal(r *buffer.Buffer) error {
|
||||||
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLOutcome, []encoding.UnmarshalField{
|
return encoding.UnmarshalComposite(r, encoding.TypeCodeSASLOutcome, []encoding.UnmarshalField{
|
||||||
{Field: &so.Code, HandleNull: func() error { return errors.New("saslOutcome.AdditionalData is required") }},
|
{Field: &so.Code, HandleNull: func() error { return errors.New("saslOutcome.AdditionalData is required") }},
|
||||||
{Field: &so.AdditionalData},
|
{Field: &so.AdditionalData},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *saslOutcome) String() string {
|
func (so *SASLOutcome) String() string {
|
||||||
return fmt.Sprintf("SaslOutcome{Code : %v, AdditionalData: %v}",
|
return fmt.Sprintf("SaslOutcome{Code : %v, AdditionalData: %v}",
|
||||||
so.Code,
|
so.Code,
|
||||||
so.AdditionalData,
|
so.AdditionalData,
|
103
link.go
103
link.go
|
@ -10,32 +10,9 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
type role bool
|
|
||||||
|
|
||||||
const (
|
|
||||||
roleSender role = false
|
|
||||||
roleReceiver role = true
|
|
||||||
)
|
|
||||||
|
|
||||||
func (rl role) String() string {
|
|
||||||
if rl {
|
|
||||||
return "Receiver"
|
|
||||||
}
|
|
||||||
return "Sender"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rl *role) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
b, err := encoding.ReadBool(r)
|
|
||||||
*rl = role(b)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rl role) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Marshal(wr, (bool)(rl))
|
|
||||||
}
|
|
||||||
|
|
||||||
// link is a unidirectional route.
|
// link is a unidirectional route.
|
||||||
//
|
//
|
||||||
// May be used for sending or receiving.
|
// May be used for sending or receiving.
|
||||||
|
@ -44,8 +21,8 @@ type link struct {
|
||||||
handle uint32 // our handle
|
handle uint32 // our handle
|
||||||
remoteHandle uint32 // remote's handle
|
remoteHandle uint32 // remote's handle
|
||||||
dynamicAddr bool // request a dynamic link address from the server
|
dynamicAddr bool // request a dynamic link address from the server
|
||||||
rx chan frameBody // sessions sends frames for this link on this channel
|
rx chan frames.FrameBody // sessions sends frames for this link on this channel
|
||||||
transfers chan performTransfer // sender uses to send transfer frames
|
transfers chan frames.PerformTransfer // sender uses to send transfer frames
|
||||||
closeOnce sync.Once // closeOnce protects close from being closed multiple times
|
closeOnce sync.Once // closeOnce protects close from being closed multiple times
|
||||||
|
|
||||||
// NOTE: `close` and `detached` BOTH need to be checked to determine if the link
|
// NOTE: `close` and `detached` BOTH need to be checked to determine if the link
|
||||||
|
@ -61,8 +38,8 @@ type link struct {
|
||||||
detachError *Error // error to send to remote on detach, set by closeWithError
|
detachError *Error // error to send to remote on detach, set by closeWithError
|
||||||
session *Session // parent session
|
session *Session // parent session
|
||||||
receiver *Receiver // allows link options to modify Receiver
|
receiver *Receiver // allows link options to modify Receiver
|
||||||
source *source
|
source *frames.Source
|
||||||
target *target
|
target *frames.Target
|
||||||
properties map[encoding.Symbol]interface{} // additional properties sent upon link attach
|
properties map[encoding.Symbol]interface{} // additional properties sent upon link attach
|
||||||
// Indicates whether we should allow detaches on disposition errors or not.
|
// Indicates whether we should allow detaches on disposition errors or not.
|
||||||
// Some AMQP servers (like Event Hubs) benefit from keeping the link open on disposition errors
|
// Some AMQP servers (like Event Hubs) benefit from keeping the link open on disposition errors
|
||||||
|
@ -97,7 +74,7 @@ type link struct {
|
||||||
|
|
||||||
func newLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
func newLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
l := &link{
|
l := &link{
|
||||||
key: linkKey{randString(40), role(r != nil)},
|
key: linkKey{randString(40), encoding.Role(r != nil)},
|
||||||
session: s,
|
session: s,
|
||||||
receiver: r,
|
receiver: r,
|
||||||
close: make(chan struct{}),
|
close: make(chan struct{}),
|
||||||
|
@ -130,12 +107,12 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
// attempting to send to a slow reader
|
// attempting to send to a slow reader
|
||||||
if isReceiver {
|
if isReceiver {
|
||||||
if l.receiver.manualCreditor != nil {
|
if l.receiver.manualCreditor != nil {
|
||||||
l.rx = make(chan frameBody, l.receiver.maxCredit)
|
l.rx = make(chan frames.FrameBody, l.receiver.maxCredit)
|
||||||
} else {
|
} else {
|
||||||
l.rx = make(chan frameBody, l.linkCredit)
|
l.rx = make(chan frames.FrameBody, l.linkCredit)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
l.rx = make(chan frameBody, 1)
|
l.rx = make(chan frames.FrameBody, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// request handle from Session.mux
|
// request handle from Session.mux
|
||||||
|
@ -157,7 +134,7 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
return nil, l.err
|
return nil, l.err
|
||||||
}
|
}
|
||||||
|
|
||||||
attach := &performAttach{
|
attach := &frames.PerformAttach{
|
||||||
Name: l.key.name,
|
Name: l.key.name,
|
||||||
Handle: l.handle,
|
Handle: l.handle,
|
||||||
ReceiverSettleMode: l.receiverSettleMode,
|
ReceiverSettleMode: l.receiverSettleMode,
|
||||||
|
@ -169,15 +146,15 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isReceiver {
|
if isReceiver {
|
||||||
attach.Role = roleReceiver
|
attach.Role = encoding.RoleReceiver
|
||||||
if attach.Source == nil {
|
if attach.Source == nil {
|
||||||
attach.Source = new(source)
|
attach.Source = new(frames.Source)
|
||||||
}
|
}
|
||||||
attach.Source.Dynamic = l.dynamicAddr
|
attach.Source.Dynamic = l.dynamicAddr
|
||||||
} else {
|
} else {
|
||||||
attach.Role = roleSender
|
attach.Role = encoding.RoleSender
|
||||||
if attach.Target == nil {
|
if attach.Target == nil {
|
||||||
attach.Target = new(target)
|
attach.Target = new(frames.Target)
|
||||||
}
|
}
|
||||||
attach.Target.Dynamic = l.dynamicAddr
|
attach.Target.Dynamic = l.dynamicAddr
|
||||||
}
|
}
|
||||||
|
@ -187,14 +164,14 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
_ = s.txFrame(attach, nil)
|
_ = s.txFrame(attach, nil)
|
||||||
|
|
||||||
// wait for response
|
// wait for response
|
||||||
var fr frameBody
|
var fr frames.FrameBody
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
return nil, s.err
|
return nil, s.err
|
||||||
case fr = <-l.rx:
|
case fr = <-l.rx:
|
||||||
}
|
}
|
||||||
debug(3, "RX: %s", fr)
|
debug(3, "RX: %s", fr)
|
||||||
resp, ok := fr.(*performAttach)
|
resp, ok := fr.(*frames.PerformAttach)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unexpected attach response: %#v", fr)
|
return nil, fmt.Errorf("unexpected attach response: %#v", fr)
|
||||||
}
|
}
|
||||||
|
@ -216,13 +193,13 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
case fr = <-l.rx:
|
case fr = <-l.rx:
|
||||||
}
|
}
|
||||||
|
|
||||||
detach, ok := fr.(*performDetach)
|
detach, ok := fr.(*frames.PerformDetach)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unexpected frame while waiting for detach: %#v", fr)
|
return nil, fmt.Errorf("unexpected frame while waiting for detach: %#v", fr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send return detach
|
// send return detach
|
||||||
fr = &performDetach{
|
fr = &frames.PerformDetach{
|
||||||
Handle: l.handle,
|
Handle: l.handle,
|
||||||
Closed: true,
|
Closed: true,
|
||||||
}
|
}
|
||||||
|
@ -256,7 +233,7 @@ func attachLink(s *Session, r *Receiver, opts []LinkOption) (*link, error) {
|
||||||
if l.dynamicAddr && resp.Target != nil {
|
if l.dynamicAddr && resp.Target != nil {
|
||||||
l.target.Address = resp.Target.Address
|
l.target.Address = resp.Target.Address
|
||||||
}
|
}
|
||||||
l.transfers = make(chan performTransfer)
|
l.transfers = make(chan frames.PerformTransfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.setSettleModes(resp)
|
err = l.setSettleModes(resp)
|
||||||
|
@ -289,14 +266,14 @@ func (l *link) countUnsettled() int {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// setSettleModes sets the settlement modes based on the resp performAttach.
|
// setSettleModes sets the settlement modes based on the resp frames.PerformAttach.
|
||||||
//
|
//
|
||||||
// If a settlement mode has been explicitly set locally and it was not honored by the
|
// If a settlement mode has been explicitly set locally and it was not honored by the
|
||||||
// server an error is returned.
|
// server an error is returned.
|
||||||
func (l *link) setSettleModes(resp *performAttach) error {
|
func (l *link) setSettleModes(resp *frames.PerformAttach) error {
|
||||||
var (
|
var (
|
||||||
localRecvSettle = l.receiverSettleMode.value()
|
localRecvSettle = receiverSettleModeValue(l.receiverSettleMode)
|
||||||
respRecvSettle = resp.ReceiverSettleMode.value()
|
respRecvSettle = receiverSettleModeValue(resp.ReceiverSettleMode)
|
||||||
)
|
)
|
||||||
if l.receiverSettleMode != nil && localRecvSettle != respRecvSettle {
|
if l.receiverSettleMode != nil && localRecvSettle != respRecvSettle {
|
||||||
return fmt.Errorf("amqp: receiver settlement mode %q requested, received %q from server", l.receiverSettleMode, &respRecvSettle)
|
return fmt.Errorf("amqp: receiver settlement mode %q requested, received %q from server", l.receiverSettleMode, &respRecvSettle)
|
||||||
|
@ -304,8 +281,8 @@ func (l *link) setSettleModes(resp *performAttach) error {
|
||||||
l.receiverSettleMode = &respRecvSettle
|
l.receiverSettleMode = &respRecvSettle
|
||||||
|
|
||||||
var (
|
var (
|
||||||
localSendSettle = l.senderSettleMode.value()
|
localSendSettle = senderSettleModeValue(l.senderSettleMode)
|
||||||
respSendSettle = resp.SenderSettleMode.value()
|
respSendSettle = senderSettleModeValue(resp.SenderSettleMode)
|
||||||
)
|
)
|
||||||
if l.senderSettleMode != nil && localSendSettle != respSendSettle {
|
if l.senderSettleMode != nil && localSendSettle != respSendSettle {
|
||||||
return fmt.Errorf("amqp: sender settlement mode %q requested, received %q from server", l.senderSettleMode, &respSendSettle)
|
return fmt.Errorf("amqp: sender settlement mode %q requested, received %q from server", l.senderSettleMode, &respSendSettle)
|
||||||
|
@ -369,7 +346,7 @@ func (l *link) mux() {
|
||||||
|
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for {
|
||||||
var outgoingTransfers chan performTransfer
|
var outgoingTransfers chan frames.PerformTransfer
|
||||||
|
|
||||||
ok, enableOutgoingTransfers := l.doFlow()
|
ok, enableOutgoingTransfers := l.doFlow()
|
||||||
|
|
||||||
|
@ -440,7 +417,7 @@ func (l *link) muxFlow(linkCredit uint32, drain bool) error {
|
||||||
|
|
||||||
debug(3, "link.muxFlow(): len(l.messages):%d - linkCredit: %d - deliveryCount: %d, inFlight: %d", len(l.messages), linkCredit, deliveryCount, len(l.receiver.inFlight.m))
|
debug(3, "link.muxFlow(): len(l.messages):%d - linkCredit: %d - deliveryCount: %d, inFlight: %d", len(l.messages), linkCredit, deliveryCount, len(l.receiver.inFlight.m))
|
||||||
|
|
||||||
fr := &performFlow{
|
fr := &frames.PerformFlow{
|
||||||
Handle: &l.handle,
|
Handle: &l.handle,
|
||||||
DeliveryCount: &deliveryCount,
|
DeliveryCount: &deliveryCount,
|
||||||
LinkCredit: &linkCredit, // max number of messages,
|
LinkCredit: &linkCredit, // max number of messages,
|
||||||
|
@ -472,7 +449,7 @@ func (l *link) muxFlow(linkCredit uint32, drain bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *link) muxReceive(fr performTransfer) error {
|
func (l *link) muxReceive(fr frames.PerformTransfer) error {
|
||||||
if !l.more {
|
if !l.more {
|
||||||
// this is the first transfer of a message,
|
// this is the first transfer of a message,
|
||||||
// record the delivery ID, message format,
|
// record the delivery ID, message format,
|
||||||
|
@ -592,7 +569,7 @@ func (l *link) muxReceive(fr performTransfer) error {
|
||||||
debug(1, "deliveryID %d before push to receiver - deliveryCount : %d - linkCredit: %d, len(messages): %d, len(inflight): %d", l.msg.deliveryID, l.deliveryCount, l.linkCredit, len(l.messages), len(l.receiver.inFlight.m))
|
debug(1, "deliveryID %d before push to receiver - deliveryCount : %d - linkCredit: %d, len(messages): %d, len(inflight): %d", l.msg.deliveryID, l.deliveryCount, l.linkCredit, len(l.messages), len(l.receiver.inFlight.m))
|
||||||
// send to receiver, this should never block due to buffering
|
// send to receiver, this should never block due to buffering
|
||||||
// and flow control.
|
// and flow control.
|
||||||
if l.receiverSettleMode.value() == ModeSecond {
|
if receiverSettleModeValue(l.receiverSettleMode) == ModeSecond {
|
||||||
l.addUnsettled(&l.msg)
|
l.addUnsettled(&l.msg)
|
||||||
}
|
}
|
||||||
l.messages <- l.msg
|
l.messages <- l.msg
|
||||||
|
@ -645,7 +622,7 @@ func (l *link) issueCredit(credit uint32) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// muxHandleFrame processes fr based on type.
|
// muxHandleFrame processes fr based on type.
|
||||||
func (l *link) muxHandleFrame(fr frameBody) error {
|
func (l *link) muxHandleFrame(fr frames.FrameBody) error {
|
||||||
var (
|
var (
|
||||||
isSender = l.receiver == nil
|
isSender = l.receiver == nil
|
||||||
errOnRejectDisposition = l.detachOnDispositionError && (isSender && (l.receiverSettleMode == nil || *l.receiverSettleMode == ModeFirst))
|
errOnRejectDisposition = l.detachOnDispositionError && (isSender && (l.receiverSettleMode == nil || *l.receiverSettleMode == ModeFirst))
|
||||||
|
@ -653,7 +630,7 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
|
|
||||||
switch fr := fr.(type) {
|
switch fr := fr.(type) {
|
||||||
// message frame
|
// message frame
|
||||||
case *performTransfer:
|
case *frames.PerformTransfer:
|
||||||
debug(3, "RX: %s", fr)
|
debug(3, "RX: %s", fr)
|
||||||
if isSender {
|
if isSender {
|
||||||
// Senders should never receive transfer frames, but handle it just in case.
|
// Senders should never receive transfer frames, but handle it just in case.
|
||||||
|
@ -667,7 +644,7 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
return l.muxReceive(*fr)
|
return l.muxReceive(*fr)
|
||||||
|
|
||||||
// flow control frame
|
// flow control frame
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
debug(3, "RX: %s", fr)
|
debug(3, "RX: %s", fr)
|
||||||
if isSender {
|
if isSender {
|
||||||
linkCredit := *fr.LinkCredit - l.deliveryCount
|
linkCredit := *fr.LinkCredit - l.deliveryCount
|
||||||
|
@ -697,7 +674,7 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
)
|
)
|
||||||
|
|
||||||
// send flow
|
// send flow
|
||||||
resp := &performFlow{
|
resp := &frames.PerformFlow{
|
||||||
Handle: &l.handle,
|
Handle: &l.handle,
|
||||||
DeliveryCount: &deliveryCount,
|
DeliveryCount: &deliveryCount,
|
||||||
LinkCredit: &linkCredit, // max number of messages
|
LinkCredit: &linkCredit, // max number of messages
|
||||||
|
@ -706,7 +683,7 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
_ = l.session.txFrame(resp, nil)
|
_ = l.session.txFrame(resp, nil)
|
||||||
|
|
||||||
// remote side is closing links
|
// remote side is closing links
|
||||||
case *performDetach:
|
case *frames.PerformDetach:
|
||||||
debug(1, "RX: %s", fr)
|
debug(1, "RX: %s", fr)
|
||||||
// don't currently support link detach and reattach
|
// don't currently support link detach and reattach
|
||||||
if !fr.Closed {
|
if !fr.Closed {
|
||||||
|
@ -718,7 +695,7 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
|
|
||||||
return fmt.Errorf("received detach frame %v", &DetachError{fr.Error})
|
return fmt.Errorf("received detach frame %v", &DetachError{fr.Error})
|
||||||
|
|
||||||
case *performDisposition:
|
case *frames.PerformDisposition:
|
||||||
debug(3, "RX: %s", fr)
|
debug(3, "RX: %s", fr)
|
||||||
|
|
||||||
// Unblock receivers waiting for message disposition
|
// Unblock receivers waiting for message disposition
|
||||||
|
@ -742,8 +719,8 @@ func (l *link) muxHandleFrame(fr frameBody) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &performDisposition{
|
resp := &frames.PerformDisposition{
|
||||||
Role: roleSender,
|
Role: encoding.RoleSender,
|
||||||
First: fr.First,
|
First: fr.First,
|
||||||
Last: fr.Last,
|
Last: fr.Last,
|
||||||
Settled: true,
|
Settled: true,
|
||||||
|
@ -838,7 +815,7 @@ func (l *link) muxDetach() {
|
||||||
detachError := l.detachError
|
detachError := l.detachError
|
||||||
l.detachErrorMu.Unlock()
|
l.detachErrorMu.Unlock()
|
||||||
|
|
||||||
fr := &performDetach{
|
fr := &frames.PerformDetach{
|
||||||
Handle: l.handle,
|
Handle: l.handle,
|
||||||
Closed: true,
|
Closed: true,
|
||||||
Error: detachError,
|
Error: detachError,
|
||||||
|
@ -852,7 +829,7 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
case fr := <-l.rx:
|
case fr := <-l.rx:
|
||||||
// discard incoming frames to avoid blocking session.mux
|
// discard incoming frames to avoid blocking session.mux
|
||||||
if fr, ok := fr.(*performDetach); ok && fr.Closed {
|
if fr, ok := fr.(*frames.PerformDetach); ok && fr.Closed {
|
||||||
l.detachReceived = true
|
l.detachReceived = true
|
||||||
}
|
}
|
||||||
case <-l.session.done:
|
case <-l.session.done:
|
||||||
|
@ -874,7 +851,7 @@ Loop:
|
||||||
// read from link until detach with Close == true is received,
|
// read from link until detach with Close == true is received,
|
||||||
// other frames are discarded.
|
// other frames are discarded.
|
||||||
case fr := <-l.rx:
|
case fr := <-l.rx:
|
||||||
if fr, ok := fr.(*performDetach); ok && fr.Closed {
|
if fr, ok := fr.(*frames.PerformDetach); ok && fr.Closed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LinkOption is a function for configuring an AMQP link.
|
// LinkOption is a function for configuring an AMQP link.
|
||||||
|
@ -78,7 +79,7 @@ func LinkName(name string) LinkOption {
|
||||||
func LinkSourceCapabilities(capabilities ...string) LinkOption {
|
func LinkSourceCapabilities(capabilities ...string) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert string to symbol
|
// Convert string to symbol
|
||||||
|
@ -96,7 +97,7 @@ func LinkSourceCapabilities(capabilities ...string) LinkOption {
|
||||||
func LinkSourceAddress(addr string) LinkOption {
|
func LinkSourceAddress(addr string) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
l.source.Address = addr
|
l.source.Address = addr
|
||||||
return nil
|
return nil
|
||||||
|
@ -107,7 +108,7 @@ func LinkSourceAddress(addr string) LinkOption {
|
||||||
func LinkTargetAddress(addr string) LinkOption {
|
func LinkTargetAddress(addr string) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.target == nil {
|
if l.target == nil {
|
||||||
l.target = new(target)
|
l.target = new(frames.Target)
|
||||||
}
|
}
|
||||||
l.target.Address = addr
|
l.target.Address = addr
|
||||||
return nil
|
return nil
|
||||||
|
@ -235,7 +236,7 @@ func LinkSelectorFilter(filter string) LinkOption {
|
||||||
func LinkSourceFilter(name string, code uint64, value interface{}) LinkOption {
|
func LinkSourceFilter(name string, code uint64, value interface{}) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
if l.source.Filter == nil {
|
if l.source.Filter == nil {
|
||||||
l.source.Filter = make(map[encoding.Symbol]*encoding.DescribedType)
|
l.source.Filter = make(map[encoding.Symbol]*encoding.DescribedType)
|
||||||
|
@ -279,7 +280,7 @@ func LinkTargetDurability(d Durability) LinkOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.target == nil {
|
if l.target == nil {
|
||||||
l.target = new(target)
|
l.target = new(frames.Target)
|
||||||
}
|
}
|
||||||
l.target.Durable = d
|
l.target.Durable = d
|
||||||
|
|
||||||
|
@ -292,13 +293,13 @@ func LinkTargetDurability(d Durability) LinkOption {
|
||||||
// Default: ExpirySessionEnd.
|
// Default: ExpirySessionEnd.
|
||||||
func LinkTargetExpiryPolicy(p ExpiryPolicy) LinkOption {
|
func LinkTargetExpiryPolicy(p ExpiryPolicy) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
err := p.validate()
|
err := encoding.ValidateExpiryPolicy(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.target == nil {
|
if l.target == nil {
|
||||||
l.target = new(target)
|
l.target = new(frames.Target)
|
||||||
}
|
}
|
||||||
l.target.ExpiryPolicy = p
|
l.target.ExpiryPolicy = p
|
||||||
|
|
||||||
|
@ -312,7 +313,7 @@ func LinkTargetExpiryPolicy(p ExpiryPolicy) LinkOption {
|
||||||
func LinkTargetTimeout(timeout uint32) LinkOption {
|
func LinkTargetTimeout(timeout uint32) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.target == nil {
|
if l.target == nil {
|
||||||
l.target = new(target)
|
l.target = new(frames.Target)
|
||||||
}
|
}
|
||||||
l.target.Timeout = timeout
|
l.target.Timeout = timeout
|
||||||
|
|
||||||
|
@ -330,7 +331,7 @@ func LinkSourceDurability(d Durability) LinkOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
l.source.Durable = d
|
l.source.Durable = d
|
||||||
|
|
||||||
|
@ -343,13 +344,13 @@ func LinkSourceDurability(d Durability) LinkOption {
|
||||||
// Default: ExpirySessionEnd.
|
// Default: ExpirySessionEnd.
|
||||||
func LinkSourceExpiryPolicy(p ExpiryPolicy) LinkOption {
|
func LinkSourceExpiryPolicy(p ExpiryPolicy) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
err := p.validate()
|
err := encoding.ValidateExpiryPolicy(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
l.source.ExpiryPolicy = p
|
l.source.ExpiryPolicy = p
|
||||||
|
|
||||||
|
@ -363,7 +364,7 @@ func LinkSourceExpiryPolicy(p ExpiryPolicy) LinkOption {
|
||||||
func LinkSourceTimeout(timeout uint32) LinkOption {
|
func LinkSourceTimeout(timeout uint32) LinkOption {
|
||||||
return func(l *link) error {
|
return func(l *link) error {
|
||||||
if l.source == nil {
|
if l.source == nil {
|
||||||
l.source = new(source)
|
l.source = new(frames.Source)
|
||||||
}
|
}
|
||||||
l.source.Timeout = timeout
|
l.source.Timeout = timeout
|
||||||
|
|
||||||
|
|
15
link_test.go
15
link_test.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ func TestLinkFlowThatNeedsToReplenishCredits(t *testing.T) {
|
||||||
txFrame := <-l.session.tx
|
txFrame := <-l.session.tx
|
||||||
|
|
||||||
switch frame := txFrame.(type) {
|
switch frame := txFrame.(type) {
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
require.False(t, frame.Drain)
|
require.False(t, frame.Drain)
|
||||||
// replenished credits: l.receiver.maxCredit-uint32(l.countUnsettled())
|
// replenished credits: l.receiver.maxCredit-uint32(l.countUnsettled())
|
||||||
require.EqualValues(t, 2, *frame.LinkCredit)
|
require.EqualValues(t, 2, *frame.LinkCredit)
|
||||||
|
@ -132,7 +133,7 @@ func TestLinkFlowWithManualCreditor(t *testing.T) {
|
||||||
txFrame := <-l.session.tx
|
txFrame := <-l.session.tx
|
||||||
|
|
||||||
switch frame := txFrame.(type) {
|
switch frame := txFrame.(type) {
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
require.False(t, frame.Drain)
|
require.False(t, frame.Drain)
|
||||||
require.EqualValues(t, 100+1, *frame.LinkCredit)
|
require.EqualValues(t, 100+1, *frame.LinkCredit)
|
||||||
default:
|
default:
|
||||||
|
@ -155,7 +156,7 @@ func TestLinkFlowWithDrain(t *testing.T) {
|
||||||
txFrame := <-l.session.tx
|
txFrame := <-l.session.tx
|
||||||
|
|
||||||
switch frame := txFrame.(type) {
|
switch frame := txFrame.(type) {
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
require.True(t, frame.Drain)
|
require.True(t, frame.Drain)
|
||||||
require.EqualValues(t, 1, *frame.LinkCredit)
|
require.EqualValues(t, 1, *frame.LinkCredit)
|
||||||
default:
|
default:
|
||||||
|
@ -163,7 +164,7 @@ func TestLinkFlowWithDrain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate the return of the flow from the service
|
// simulate the return of the flow from the service
|
||||||
err := l.muxHandleFrame(&performFlow{
|
err := l.muxHandleFrame(&frames.PerformFlow{
|
||||||
Drain: true,
|
Drain: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -195,17 +196,17 @@ func TestLinkFlowWithManualCreditorAndNoFlowNeeded(t *testing.T) {
|
||||||
|
|
||||||
func newTestLink(t *testing.T) *link {
|
func newTestLink(t *testing.T) *link {
|
||||||
l := &link{
|
l := &link{
|
||||||
source: &source{},
|
source: &frames.Source{},
|
||||||
receiver: &Receiver{
|
receiver: &Receiver{
|
||||||
// adding just enough so the debug() print will still work...
|
// adding just enough so the debug() print will still work...
|
||||||
// debug(1, "FLOW Link Mux half: source: %s, inflight: %d, credit: %d, deliveryCount: %d, messages: %d, unsettled: %d, maxCredit : %d, settleMode: %s", l.source.Address, len(l.receiver.inFlight.m), l.linkCredit, l.deliveryCount, len(l.messages), l.countUnsettled(), l.receiver.maxCredit, l.receiverSettleMode.String())
|
// debug(1, "FLOW Link Mux half: source: %s, inflight: %d, credit: %d, deliveryCount: %d, messages: %d, unsettled: %d, maxCredit : %d, settleMode: %s", l.source.Address, len(l.receiver.inFlight.m), l.linkCredit, l.deliveryCount, len(l.messages), l.countUnsettled(), l.receiver.maxCredit, l.receiverSettleMode.String())
|
||||||
inFlight: inFlight{},
|
inFlight: inFlight{},
|
||||||
},
|
},
|
||||||
session: &Session{
|
session: &Session{
|
||||||
tx: make(chan frameBody, 100),
|
tx: make(chan frames.FrameBody, 100),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
},
|
},
|
||||||
rx: make(chan frameBody, 100),
|
rx: make(chan frames.FrameBody, 100),
|
||||||
receiverReady: make(chan struct{}, 1),
|
receiverReady: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,18 +14,19 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
var exampleFrames = []struct {
|
var exampleFrames = []struct {
|
||||||
label string
|
label string
|
||||||
frame frame
|
frame frames.Frame
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
label: "transfer",
|
label: "transfer",
|
||||||
frame: frame{
|
frame: frames.Frame{
|
||||||
type_: frameTypeAMQP,
|
Type: frameTypeAMQP,
|
||||||
channel: 10,
|
Channel: 10,
|
||||||
body: &performTransfer{
|
Body: &frames.PerformTransfer{
|
||||||
Handle: 34983,
|
Handle: 34983,
|
||||||
DeliveryID: uint32Ptr(564),
|
DeliveryID: uint32Ptr(564),
|
||||||
DeliveryTag: []byte("foo tag"),
|
DeliveryTag: []byte("foo tag"),
|
||||||
|
@ -59,19 +60,19 @@ func TestFrameMarshalUnmarshal(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
want := tt.frame
|
want := tt.frame
|
||||||
if header.Channel != want.channel {
|
if header.Channel != want.Channel {
|
||||||
t.Errorf("Expected channel to be %d, but it is %d", want.channel, header.Channel)
|
t.Errorf("Expected channel to be %d, but it is %d", want.Channel, header.Channel)
|
||||||
}
|
}
|
||||||
if header.FrameType != want.type_ {
|
if header.FrameType != want.Type {
|
||||||
t.Errorf("Expected channel to be %d, but it is %d", want.type_, header.FrameType)
|
t.Errorf("Expected channel to be %d, but it is %d", want.Type, header.FrameType)
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, err := parseFrameBody(&buf)
|
payload, err := parseFrameBody(&buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%+v", err)
|
t.Fatalf("%+v", err)
|
||||||
}
|
}
|
||||||
if !testEqual(want.body, payload) {
|
if !testEqual(want.Body, payload) {
|
||||||
t.Errorf("Roundtrip produced different results:\n %s", testDiff(want.body, payload))
|
t.Errorf("Roundtrip produced different results:\n %s", testDiff(want.Body, payload))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -263,7 +264,7 @@ var (
|
||||||
remoteChannel = uint16(4321)
|
remoteChannel = uint16(4321)
|
||||||
|
|
||||||
protoTypes = []interface{}{
|
protoTypes = []interface{}{
|
||||||
&performOpen{
|
&frames.PerformOpen{
|
||||||
ContainerID: "foo",
|
ContainerID: "foo",
|
||||||
Hostname: "bar.host",
|
Hostname: "bar.host",
|
||||||
MaxFrameSize: 4200,
|
MaxFrameSize: 4200,
|
||||||
|
@ -276,7 +277,7 @@ var (
|
||||||
"fooProp": int32(45),
|
"fooProp": int32(45),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performBegin{
|
&frames.PerformBegin{
|
||||||
RemoteChannel: &remoteChannel,
|
RemoteChannel: &remoteChannel,
|
||||||
NextOutgoingID: 730000,
|
NextOutgoingID: 730000,
|
||||||
IncomingWindow: 9876654,
|
IncomingWindow: 9876654,
|
||||||
|
@ -288,13 +289,13 @@ var (
|
||||||
"fooProp": int32(45),
|
"fooProp": int32(45),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performAttach{
|
&frames.PerformAttach{
|
||||||
Name: "fooName",
|
Name: "fooName",
|
||||||
Handle: 435982,
|
Handle: 435982,
|
||||||
Role: roleSender,
|
Role: encoding.RoleSender,
|
||||||
SenderSettleMode: sndSettle(ModeMixed),
|
SenderSettleMode: sndSettle(ModeMixed),
|
||||||
ReceiverSettleMode: rcvSettle(ModeSecond),
|
ReceiverSettleMode: rcvSettle(ModeSecond),
|
||||||
Source: &source{
|
Source: &frames.Source{
|
||||||
Address: "fooAddr",
|
Address: "fooAddr",
|
||||||
Durable: DurabilityUnsettledState,
|
Durable: DurabilityUnsettledState,
|
||||||
ExpiryPolicy: ExpiryLinkDetach,
|
ExpiryPolicy: ExpiryLinkDetach,
|
||||||
|
@ -313,7 +314,7 @@ var (
|
||||||
Outcomes: []encoding.Symbol{"amqp:accepted:list"},
|
Outcomes: []encoding.Symbol{"amqp:accepted:list"},
|
||||||
Capabilities: []encoding.Symbol{"barCap"},
|
Capabilities: []encoding.Symbol{"barCap"},
|
||||||
},
|
},
|
||||||
Target: &target{
|
Target: &frames.Target{
|
||||||
Address: "fooAddr",
|
Address: "fooAddr",
|
||||||
Durable: DurabilityUnsettledState,
|
Durable: DurabilityUnsettledState,
|
||||||
ExpiryPolicy: ExpiryLinkDetach,
|
ExpiryPolicy: ExpiryLinkDetach,
|
||||||
|
@ -336,11 +337,11 @@ var (
|
||||||
"fooProp": int32(45),
|
"fooProp": int32(45),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
role(true),
|
encoding.Role(true),
|
||||||
&encoding.Unsettled{
|
&encoding.Unsettled{
|
||||||
"fooDeliveryTag": &encoding.StateAccepted{},
|
"fooDeliveryTag": &encoding.StateAccepted{},
|
||||||
},
|
},
|
||||||
&source{
|
&frames.Source{
|
||||||
Address: "fooAddr",
|
Address: "fooAddr",
|
||||||
Durable: DurabilityUnsettledState,
|
Durable: DurabilityUnsettledState,
|
||||||
ExpiryPolicy: ExpiryLinkDetach,
|
ExpiryPolicy: ExpiryLinkDetach,
|
||||||
|
@ -359,7 +360,7 @@ var (
|
||||||
Outcomes: []encoding.Symbol{"amqp:accepted:list"},
|
Outcomes: []encoding.Symbol{"amqp:accepted:list"},
|
||||||
Capabilities: []encoding.Symbol{"barCap"},
|
Capabilities: []encoding.Symbol{"barCap"},
|
||||||
},
|
},
|
||||||
&target{
|
&frames.Target{
|
||||||
Address: "fooAddr",
|
Address: "fooAddr",
|
||||||
Durable: DurabilityUnsettledState,
|
Durable: DurabilityUnsettledState,
|
||||||
ExpiryPolicy: ExpiryLinkDetach,
|
ExpiryPolicy: ExpiryLinkDetach,
|
||||||
|
@ -370,7 +371,7 @@ var (
|
||||||
},
|
},
|
||||||
Capabilities: []encoding.Symbol{"barCap"},
|
Capabilities: []encoding.Symbol{"barCap"},
|
||||||
},
|
},
|
||||||
&performFlow{
|
&frames.PerformFlow{
|
||||||
NextIncomingID: uint32Ptr(354),
|
NextIncomingID: uint32Ptr(354),
|
||||||
IncomingWindow: 4352,
|
IncomingWindow: 4352,
|
||||||
NextOutgoingID: 85324,
|
NextOutgoingID: 85324,
|
||||||
|
@ -385,7 +386,7 @@ var (
|
||||||
"fooProp": int32(45),
|
"fooProp": int32(45),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performTransfer{
|
&frames.PerformTransfer{
|
||||||
Handle: 34983,
|
Handle: 34983,
|
||||||
DeliveryID: uint32Ptr(564),
|
DeliveryID: uint32Ptr(564),
|
||||||
DeliveryTag: []byte("foo tag"),
|
DeliveryTag: []byte("foo tag"),
|
||||||
|
@ -399,15 +400,15 @@ var (
|
||||||
Batchable: true,
|
Batchable: true,
|
||||||
Payload: []byte("very important payload"),
|
Payload: []byte("very important payload"),
|
||||||
},
|
},
|
||||||
&performDisposition{
|
&frames.PerformDisposition{
|
||||||
Role: roleSender,
|
Role: encoding.RoleSender,
|
||||||
First: 5644444,
|
First: 5644444,
|
||||||
Last: uint32Ptr(423),
|
Last: uint32Ptr(423),
|
||||||
Settled: true,
|
Settled: true,
|
||||||
State: &encoding.StateReleased{},
|
State: &encoding.StateReleased{},
|
||||||
Batchable: true,
|
Batchable: true,
|
||||||
},
|
},
|
||||||
&performDetach{
|
&frames.PerformDetach{
|
||||||
Handle: 4352,
|
Handle: 4352,
|
||||||
Closed: true,
|
Closed: true,
|
||||||
Error: &Error{
|
Error: &Error{
|
||||||
|
@ -419,7 +420,7 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performDetach{
|
&frames.PerformDetach{
|
||||||
Handle: 4352,
|
Handle: 4352,
|
||||||
Closed: true,
|
Closed: true,
|
||||||
Error: &Error{
|
Error: &Error{
|
||||||
|
@ -443,7 +444,7 @@ var (
|
||||||
"and": uint16(875),
|
"and": uint16(875),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performEnd{
|
&frames.PerformEnd{
|
||||||
Error: &Error{
|
Error: &Error{
|
||||||
Condition: ErrorNotAllowed,
|
Condition: ErrorNotAllowed,
|
||||||
Description: "foo description",
|
Description: "foo description",
|
||||||
|
@ -453,7 +454,7 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&performClose{
|
&frames.PerformClose{
|
||||||
Error: &Error{
|
Error: &Error{
|
||||||
Condition: ErrorNotAllowed,
|
Condition: ErrorNotAllowed,
|
||||||
Description: "foo description",
|
Description: "foo description",
|
||||||
|
@ -552,22 +553,22 @@ var (
|
||||||
encoding.LifetimePolicy(encoding.TypeCodeDeleteOnClose),
|
encoding.LifetimePolicy(encoding.TypeCodeDeleteOnClose),
|
||||||
SenderSettleMode(1),
|
SenderSettleMode(1),
|
||||||
ReceiverSettleMode(1),
|
ReceiverSettleMode(1),
|
||||||
&saslInit{
|
&frames.SASLInit{
|
||||||
Mechanism: "FOO",
|
Mechanism: "FOO",
|
||||||
InitialResponse: []byte("BAR\x00RESPONSE\x00"),
|
InitialResponse: []byte("BAR\x00RESPONSE\x00"),
|
||||||
Hostname: "me",
|
Hostname: "me",
|
||||||
},
|
},
|
||||||
&saslMechanisms{
|
&frames.SASLMechanisms{
|
||||||
Mechanisms: []encoding.Symbol{"FOO", "BAR", "BAZ"},
|
Mechanisms: []encoding.Symbol{"FOO", "BAR", "BAZ"},
|
||||||
},
|
},
|
||||||
&saslChallenge{
|
&frames.SASLChallenge{
|
||||||
Challenge: []byte("BAR\x00CHALLENGE\x00"),
|
Challenge: []byte("BAR\x00CHALLENGE\x00"),
|
||||||
},
|
},
|
||||||
&saslResponse{
|
&frames.SASLResponse{
|
||||||
Response: []byte("BAR\x00RESPONSE\x00"),
|
Response: []byte("BAR\x00RESPONSE\x00"),
|
||||||
},
|
},
|
||||||
&saslOutcome{
|
&frames.SASLOutcome{
|
||||||
Code: codeSASLSysPerm,
|
Code: encoding.CodeSASLSysPerm,
|
||||||
AdditionalData: []byte("here's some info for you..."),
|
AdditionalData: []byte("here's some info for you..."),
|
||||||
},
|
},
|
||||||
encoding.Milliseconds(10 * time.Second),
|
encoding.Milliseconds(10 * time.Second),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageDisposition struct {
|
type messageDisposition struct {
|
||||||
|
@ -53,7 +54,7 @@ func (r *Receiver) HandleMessage(ctx context.Context, handle func(*Message) erro
|
||||||
msg.receiver = r
|
msg.receiver = r
|
||||||
// we only need to track message disposition for mode second
|
// we only need to track message disposition for mode second
|
||||||
// spec : http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-receiver-settle-mode
|
// spec : http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-receiver-settle-mode
|
||||||
if r.link.receiverSettleMode.value() == ModeSecond {
|
if receiverSettleModeValue(r.link.receiverSettleMode) == ModeSecond {
|
||||||
go trackCompletion(msg)
|
go trackCompletion(msg)
|
||||||
}
|
}
|
||||||
// tracks messages until exiting handler
|
// tracks messages until exiting handler
|
||||||
|
@ -255,8 +256,8 @@ func (r *Receiver) dispositionBatcher() {
|
||||||
|
|
||||||
// sendDisposition sends a disposition frame to the peer
|
// sendDisposition sends a disposition frame to the peer
|
||||||
func (r *Receiver) sendDisposition(first uint32, last *uint32, state interface{}) error {
|
func (r *Receiver) sendDisposition(first uint32, last *uint32, state interface{}) error {
|
||||||
fr := &performDisposition{
|
fr := &frames.PerformDisposition{
|
||||||
Role: roleReceiver,
|
Role: encoding.RoleReceiver,
|
||||||
First: first,
|
First: first,
|
||||||
Last: last,
|
Last: last,
|
||||||
Settled: r.link.receiverSettleMode == nil || *r.link.receiverSettleMode == ModeFirst,
|
Settled: r.link.receiverSettleMode == nil || *r.link.receiverSettleMode == ModeFirst,
|
||||||
|
|
59
sasl.go
59
sasl.go
|
@ -3,15 +3,8 @@ package amqp
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
)
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
|
|
||||||
// SASL Codes
|
|
||||||
const (
|
|
||||||
codeSASLOK saslCode = iota // Connection authentication succeeded.
|
|
||||||
codeSASLAuth // Connection authentication failed due to an unspecified problem with the supplied credentials.
|
|
||||||
codeSASLSysPerm // Connection authentication failed due to a system error that is unlikely to be corrected without intervention.
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SASL Mechanisms
|
// SASL Mechanisms
|
||||||
|
@ -26,18 +19,6 @@ const (
|
||||||
frameTypeSASL = 0x1
|
frameTypeSASL = 0x1
|
||||||
)
|
)
|
||||||
|
|
||||||
type saslCode uint8
|
|
||||||
|
|
||||||
func (s saslCode) Marshal(wr *buffer.Buffer) error {
|
|
||||||
return encoding.Marshal(wr, uint8(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *saslCode) Unmarshal(r *buffer.Buffer) error {
|
|
||||||
n, err := encoding.ReadUbyte(r)
|
|
||||||
*s = saslCode(n)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnSASLPlain enables SASL PLAIN authentication for the connection.
|
// ConnSASLPlain enables SASL PLAIN authentication for the connection.
|
||||||
//
|
//
|
||||||
// SASL PLAIN transmits credentials in plain text and should only be used
|
// SASL PLAIN transmits credentials in plain text and should only be used
|
||||||
|
@ -53,15 +34,15 @@ func ConnSASLPlain(username, password string) ConnOption {
|
||||||
// add the handler the the map
|
// add the handler the the map
|
||||||
c.saslHandlers[saslMechanismPLAIN] = func() stateFunc {
|
c.saslHandlers[saslMechanismPLAIN] = func() stateFunc {
|
||||||
// send saslInit with PLAIN payload
|
// send saslInit with PLAIN payload
|
||||||
init := &saslInit{
|
init := &frames.SASLInit{
|
||||||
Mechanism: "PLAIN",
|
Mechanism: "PLAIN",
|
||||||
InitialResponse: []byte("\x00" + username + "\x00" + password),
|
InitialResponse: []byte("\x00" + username + "\x00" + password),
|
||||||
Hostname: "",
|
Hostname: "",
|
||||||
}
|
}
|
||||||
debug(1, "TX: %s", init)
|
debug(1, "TX: %s", init)
|
||||||
c.err = c.writeFrame(frame{
|
c.err = c.writeFrame(frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
body: init,
|
Body: init,
|
||||||
})
|
})
|
||||||
if c.err != nil {
|
if c.err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -84,14 +65,14 @@ func ConnSASLAnonymous() ConnOption {
|
||||||
|
|
||||||
// add the handler the the map
|
// add the handler the the map
|
||||||
c.saslHandlers[saslMechanismANONYMOUS] = func() stateFunc {
|
c.saslHandlers[saslMechanismANONYMOUS] = func() stateFunc {
|
||||||
init := &saslInit{
|
init := &frames.SASLInit{
|
||||||
Mechanism: saslMechanismANONYMOUS,
|
Mechanism: saslMechanismANONYMOUS,
|
||||||
InitialResponse: []byte("anonymous"),
|
InitialResponse: []byte("anonymous"),
|
||||||
}
|
}
|
||||||
debug(1, "TX: %s", init)
|
debug(1, "TX: %s", init)
|
||||||
c.err = c.writeFrame(frame{
|
c.err = c.writeFrame(frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
body: init,
|
Body: init,
|
||||||
})
|
})
|
||||||
if c.err != nil {
|
if c.err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -149,9 +130,9 @@ func (s saslXOAUTH2Handler) init() stateFunc {
|
||||||
if s.maxFrameSizeOverride > s.conn.peerMaxFrameSize {
|
if s.maxFrameSizeOverride > s.conn.peerMaxFrameSize {
|
||||||
s.conn.peerMaxFrameSize = s.maxFrameSizeOverride
|
s.conn.peerMaxFrameSize = s.maxFrameSizeOverride
|
||||||
}
|
}
|
||||||
s.conn.err = s.conn.writeFrame(frame{
|
s.conn.err = s.conn.writeFrame(frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
body: &saslInit{
|
Body: &frames.SASLInit{
|
||||||
Mechanism: saslMechanismXOAUTH2,
|
Mechanism: saslMechanismXOAUTH2,
|
||||||
InitialResponse: s.response,
|
InitialResponse: s.response,
|
||||||
},
|
},
|
||||||
|
@ -172,10 +153,10 @@ func (s saslXOAUTH2Handler) step() stateFunc {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v := fr.body.(type) {
|
switch v := fr.Body.(type) {
|
||||||
case *saslOutcome:
|
case *frames.SASLOutcome:
|
||||||
// check if auth succeeded
|
// check if auth succeeded
|
||||||
if v.Code != codeSASLOK {
|
if v.Code != encoding.CodeSASLOK {
|
||||||
s.conn.err = fmt.Errorf("SASL XOAUTH2 auth failed with code %#00x: %s : %s",
|
s.conn.err = fmt.Errorf("SASL XOAUTH2 auth failed with code %#00x: %s : %s",
|
||||||
v.Code, v.AdditionalData, s.errorResponse)
|
v.Code, v.AdditionalData, s.errorResponse)
|
||||||
return nil
|
return nil
|
||||||
|
@ -184,14 +165,14 @@ func (s saslXOAUTH2Handler) step() stateFunc {
|
||||||
// return to c.negotiateProto
|
// return to c.negotiateProto
|
||||||
s.conn.saslComplete = true
|
s.conn.saslComplete = true
|
||||||
return s.conn.negotiateProto
|
return s.conn.negotiateProto
|
||||||
case *saslChallenge:
|
case *frames.SASLChallenge:
|
||||||
if s.errorResponse == nil {
|
if s.errorResponse == nil {
|
||||||
s.errorResponse = v.Challenge
|
s.errorResponse = v.Challenge
|
||||||
|
|
||||||
// The SASL protocol requires clients to send an empty response to this challenge.
|
// The SASL protocol requires clients to send an empty response to this challenge.
|
||||||
s.conn.err = s.conn.writeFrame(frame{
|
s.conn.err = s.conn.writeFrame(frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
body: &saslResponse{
|
Body: &frames.SASLResponse{
|
||||||
Response: []byte{},
|
Response: []byte{},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -202,7 +183,7 @@ func (s saslXOAUTH2Handler) step() stateFunc {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
s.conn.err = fmt.Errorf("unexpected frame type %T", fr.body)
|
s.conn.err = fmt.Errorf("unexpected frame type %T", fr.Body)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
95
sasl_test.go
95
sasl_test.go
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
"github.com/Azure/go-amqp/internal/testconn"
|
"github.com/Azure/go-amqp/internal/testconn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -79,21 +80,21 @@ func TestSaslXOAUTH2EmptyUsername(t *testing.T) {
|
||||||
func TestConnSASLXOAUTH2AuthSuccess(t *testing.T) {
|
func TestConnSASLXOAUTH2AuthSuccess(t *testing.T) {
|
||||||
buf, err := peerResponse(
|
buf, err := peerResponse(
|
||||||
[]byte("AMQP\x03\x01\x00\x00"),
|
[]byte("AMQP\x03\x01\x00\x00"),
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
Body: &frames.SASLMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslOutcome{Code: codeSASLOK},
|
Body: &frames.SASLOutcome{Code: encoding.CodeSASLOK},
|
||||||
},
|
},
|
||||||
[]byte("AMQP\x00\x01\x00\x00"),
|
[]byte("AMQP\x00\x01\x00\x00"),
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeAMQP,
|
Type: frameTypeAMQP,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &performOpen{},
|
Body: &frames.PerformOpen{},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -114,15 +115,15 @@ func TestConnSASLXOAUTH2AuthSuccess(t *testing.T) {
|
||||||
func TestConnSASLXOAUTH2AuthFail(t *testing.T) {
|
func TestConnSASLXOAUTH2AuthFail(t *testing.T) {
|
||||||
buf, err := peerResponse(
|
buf, err := peerResponse(
|
||||||
[]byte("AMQP\x03\x01\x00\x00"),
|
[]byte("AMQP\x03\x01\x00\x00"),
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
Body: &frames.SASLMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslOutcome{Code: codeSASLAuth},
|
Body: &frames.SASLOutcome{Code: encoding.CodeSASLAuth},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ func TestConnSASLXOAUTH2AuthFail(t *testing.T) {
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
t.Errorf("authentication is expected to fail ")
|
t.Errorf("authentication is expected to fail ")
|
||||||
case !strings.Contains(err.Error(), fmt.Sprintf("code %#00x", codeSASLAuth)):
|
case !strings.Contains(err.Error(), fmt.Sprintf("code %#00x", encoding.CodeSASLAuth)):
|
||||||
t.Errorf("unexpected connection failure : %s", err)
|
t.Errorf("unexpected connection failure : %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,20 +149,20 @@ func TestConnSASLXOAUTH2AuthFail(t *testing.T) {
|
||||||
func TestConnSASLXOAUTH2AuthFailWithErrorResponse(t *testing.T) {
|
func TestConnSASLXOAUTH2AuthFailWithErrorResponse(t *testing.T) {
|
||||||
buf, err := peerResponse(
|
buf, err := peerResponse(
|
||||||
[]byte("AMQP\x03\x01\x00\x00"),
|
[]byte("AMQP\x03\x01\x00\x00"),
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
Body: &frames.SASLMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslChallenge{Challenge: []byte("{ \"status\":\"401\", \"schemes\":\"bearer\", \"scope\":\"https://mail.google.com/\" }")},
|
Body: &frames.SASLChallenge{Challenge: []byte("{ \"status\":\"401\", \"schemes\":\"bearer\", \"scope\":\"https://mail.google.com/\" }")},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslOutcome{Code: codeSASLAuth},
|
Body: &frames.SASLOutcome{Code: encoding.CodeSASLAuth},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -179,7 +180,7 @@ func TestConnSASLXOAUTH2AuthFailWithErrorResponse(t *testing.T) {
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
t.Errorf("authentication is expected to fail ")
|
t.Errorf("authentication is expected to fail ")
|
||||||
case !strings.Contains(err.Error(), fmt.Sprintf("code %#00x", codeSASLAuth)):
|
case !strings.Contains(err.Error(), fmt.Sprintf("code %#00x", encoding.CodeSASLAuth)):
|
||||||
t.Errorf("unexpected connection failure : %s", err)
|
t.Errorf("unexpected connection failure : %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,20 +188,20 @@ func TestConnSASLXOAUTH2AuthFailWithErrorResponse(t *testing.T) {
|
||||||
func TestConnSASLXOAUTH2AuthFailsAdditionalErrorResponse(t *testing.T) {
|
func TestConnSASLXOAUTH2AuthFailsAdditionalErrorResponse(t *testing.T) {
|
||||||
buf, err := peerResponse(
|
buf, err := peerResponse(
|
||||||
[]byte("AMQP\x03\x01\x00\x00"),
|
[]byte("AMQP\x03\x01\x00\x00"),
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
Body: &frames.SASLMechanisms{Mechanisms: []encoding.Symbol{saslMechanismXOAUTH2}},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslChallenge{Challenge: []byte("fail1")},
|
Body: &frames.SASLChallenge{Challenge: []byte("fail1")},
|
||||||
},
|
},
|
||||||
frame{
|
frames.Frame{
|
||||||
type_: frameTypeSASL,
|
Type: frameTypeSASL,
|
||||||
channel: 0,
|
Channel: 0,
|
||||||
body: &saslChallenge{Challenge: []byte("fail2")},
|
Body: &frames.SASLChallenge{Challenge: []byte("fail2")},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -227,7 +228,7 @@ func peerResponse(items ...interface{}) ([]byte, error) {
|
||||||
buf := make([]byte, 0)
|
buf := make([]byte, 0)
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
switch v := item.(type) {
|
switch v := item.(type) {
|
||||||
case frame:
|
case frames.Frame:
|
||||||
b := &buffer.Buffer{}
|
b := &buffer.Buffer{}
|
||||||
e := writeFrame(b, v)
|
e := writeFrame(b, v)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/buffer"
|
"github.com/Azure/go-amqp/internal/buffer"
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sender sends messages on a single AMQP link.
|
// Sender sends messages on a single AMQP link.
|
||||||
|
@ -99,7 +100,7 @@ func (s *Sender) send(ctx context.Context, msg *Message) (chan encoding.Delivery
|
||||||
s.nextDeliveryTag++
|
s.nextDeliveryTag++
|
||||||
}
|
}
|
||||||
|
|
||||||
fr := performTransfer{
|
fr := frames.PerformTransfer{
|
||||||
Handle: s.link.handle,
|
Handle: s.link.handle,
|
||||||
DeliveryID: &deliveryID,
|
DeliveryID: &deliveryID,
|
||||||
DeliveryTag: deliveryTag,
|
DeliveryTag: deliveryTag,
|
||||||
|
@ -121,7 +122,7 @@ func (s *Sender) send(ctx context.Context, msg *Message) (chan encoding.Delivery
|
||||||
fr.Settled = senderSettled
|
fr.Settled = senderSettled
|
||||||
|
|
||||||
// set done on last frame
|
// set done on last frame
|
||||||
fr.done = make(chan encoding.DeliveryState, 1)
|
fr.Done = make(chan encoding.DeliveryState, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -138,7 +139,7 @@ func (s *Sender) send(ctx context.Context, msg *Message) (chan encoding.Delivery
|
||||||
fr.MessageFormat = nil
|
fr.MessageFormat = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fr.done, nil
|
return fr.Done, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address returns the link's address.
|
// Address returns the link's address.
|
||||||
|
|
83
session.go
83
session.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Azure/go-amqp/internal/encoding"
|
"github.com/Azure/go-amqp/internal/encoding"
|
||||||
|
"github.com/Azure/go-amqp/internal/frames"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Session is an AMQP session.
|
// Session is an AMQP session.
|
||||||
|
@ -16,9 +17,9 @@ type Session struct {
|
||||||
channel uint16 // session's local channel
|
channel uint16 // session's local channel
|
||||||
remoteChannel uint16 // session's remote channel, owned by conn.mux
|
remoteChannel uint16 // session's remote channel, owned by conn.mux
|
||||||
conn *conn // underlying conn
|
conn *conn // underlying conn
|
||||||
rx chan frame // frames destined for this session are sent on this chan by conn.mux
|
rx chan frames.Frame // frames destined for this session are sent on this chan by conn.mux
|
||||||
tx chan frameBody // non-transfer frames to be sent; session must track disposition
|
tx chan frames.FrameBody // non-transfer frames to be sent; session must track disposition
|
||||||
txTransfer chan *performTransfer // transfer frames to be sent; session must track disposition
|
txTransfer chan *frames.PerformTransfer // transfer frames to be sent; session must track disposition
|
||||||
|
|
||||||
// flow control
|
// flow control
|
||||||
incomingWindow uint32
|
incomingWindow uint32
|
||||||
|
@ -41,9 +42,9 @@ func newSession(c *conn, channel uint16) *Session {
|
||||||
return &Session{
|
return &Session{
|
||||||
conn: c,
|
conn: c,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
rx: make(chan frame),
|
rx: make(chan frames.Frame),
|
||||||
tx: make(chan frameBody),
|
tx: make(chan frames.FrameBody),
|
||||||
txTransfer: make(chan *performTransfer),
|
txTransfer: make(chan *frames.PerformTransfer),
|
||||||
incomingWindow: DefaultWindow,
|
incomingWindow: DefaultWindow,
|
||||||
outgoingWindow: DefaultWindow,
|
outgoingWindow: DefaultWindow,
|
||||||
handleMax: DefaultMaxLinks - 1,
|
handleMax: DefaultMaxLinks - 1,
|
||||||
|
@ -73,12 +74,12 @@ func (s *Session) Close(ctx context.Context) error {
|
||||||
|
|
||||||
// txFrame sends a frame to the connWriter.
|
// txFrame sends a frame to the connWriter.
|
||||||
// it returns an error if the connection has been closed.
|
// it returns an error if the connection has been closed.
|
||||||
func (s *Session) txFrame(p frameBody, done chan encoding.DeliveryState) error {
|
func (s *Session) txFrame(p frames.FrameBody, done chan encoding.DeliveryState) error {
|
||||||
return s.conn.wantWriteFrame(frame{
|
return s.conn.wantWriteFrame(frames.Frame{
|
||||||
type_: frameTypeAMQP,
|
Type: frameTypeAMQP,
|
||||||
channel: s.channel,
|
Channel: s.channel,
|
||||||
body: p,
|
Body: p,
|
||||||
done: done,
|
Done: done,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ func (s *Session) NewSender(opts ...LinkOption) (*Sender, error) {
|
||||||
return &Sender{link: l}, nil
|
return &Sender{link: l}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) mux(remoteBegin *performBegin) {
|
func (s *Session) mux(remoteBegin *frames.PerformBegin) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// clean up session record in conn.mux()
|
// clean up session record in conn.mux()
|
||||||
select {
|
select {
|
||||||
|
@ -173,14 +174,14 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
|
|
||||||
// session is being closed by user
|
// session is being closed by user
|
||||||
case <-s.close:
|
case <-s.close:
|
||||||
_ = s.txFrame(&performEnd{}, nil)
|
_ = s.txFrame(&frames.PerformEnd{}, nil)
|
||||||
|
|
||||||
// discard frames until End is received or conn closed
|
// discard frames until End is received or conn closed
|
||||||
EndLoop:
|
EndLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case fr := <-s.rx:
|
case fr := <-s.rx:
|
||||||
_, ok := fr.body.(*performEnd)
|
_, ok := fr.Body.(*frames.PerformEnd)
|
||||||
if ok {
|
if ok {
|
||||||
break EndLoop
|
break EndLoop
|
||||||
}
|
}
|
||||||
|
@ -221,12 +222,12 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
|
|
||||||
// incoming frame for link
|
// incoming frame for link
|
||||||
case fr := <-s.rx:
|
case fr := <-s.rx:
|
||||||
debug(1, "RX(Session): %s", fr.body)
|
debug(1, "RX(Session): %s", fr.Body)
|
||||||
|
|
||||||
switch body := fr.body.(type) {
|
switch body := fr.Body.(type) {
|
||||||
// Disposition frames can reference transfers from more than one
|
// Disposition frames can reference transfers from more than one
|
||||||
// link. Send this frame to all of them.
|
// link. Send this frame to all of them.
|
||||||
case *performDisposition:
|
case *frames.PerformDisposition:
|
||||||
start := body.First
|
start := body.First
|
||||||
end := start
|
end := start
|
||||||
if body.Last != nil {
|
if body.Last != nil {
|
||||||
|
@ -234,7 +235,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
}
|
}
|
||||||
for deliveryID := start; deliveryID <= end; deliveryID++ {
|
for deliveryID := start; deliveryID <= end; deliveryID++ {
|
||||||
handles := handlesByDeliveryID
|
handles := handlesByDeliveryID
|
||||||
if body.Role == roleSender {
|
if body.Role == encoding.RoleSender {
|
||||||
handles = handlesByRemoteDeliveryID
|
handles = handlesByRemoteDeliveryID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +245,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
}
|
}
|
||||||
delete(handles, deliveryID)
|
delete(handles, deliveryID)
|
||||||
|
|
||||||
if body.Settled && body.Role == roleReceiver {
|
if body.Settled && body.Role == encoding.RoleReceiver {
|
||||||
// check if settlement confirmation was requested, if so
|
// check if settlement confirmation was requested, if so
|
||||||
// confirm by closing channel
|
// confirm by closing channel
|
||||||
if done, ok := settlementByDeliveryID[deliveryID]; ok {
|
if done, ok := settlementByDeliveryID[deliveryID]; ok {
|
||||||
|
@ -262,15 +263,15 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
s.muxFrameToLink(link, fr.body)
|
s.muxFrameToLink(link, fr.Body)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
if body.NextIncomingID == nil {
|
if body.NextIncomingID == nil {
|
||||||
// This is a protocol error:
|
// This is a protocol error:
|
||||||
// "[...] MUST be set if the peer has received
|
// "[...] MUST be set if the peer has received
|
||||||
// the begin frame for the session"
|
// the begin frame for the session"
|
||||||
_ = s.txFrame(&performEnd{
|
_ = s.txFrame(&frames.PerformEnd{
|
||||||
Error: &Error{
|
Error: &Error{
|
||||||
Condition: ErrorNotAllowed,
|
Condition: ErrorNotAllowed,
|
||||||
Description: "next-incoming-id not set after session established",
|
Description: "next-incoming-id not set after session established",
|
||||||
|
@ -306,13 +307,13 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
s.muxFrameToLink(link, fr.body)
|
s.muxFrameToLink(link, fr.Body)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.Echo {
|
if body.Echo {
|
||||||
niID := nextIncomingID
|
niID := nextIncomingID
|
||||||
resp := &performFlow{
|
resp := &frames.PerformFlow{
|
||||||
NextIncomingID: &niID,
|
NextIncomingID: &niID,
|
||||||
IncomingWindow: s.incomingWindow,
|
IncomingWindow: s.incomingWindow,
|
||||||
NextOutgoingID: nextOutgoingID,
|
NextOutgoingID: nextOutgoingID,
|
||||||
|
@ -322,7 +323,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
_ = s.txFrame(resp, nil)
|
_ = s.txFrame(resp, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *performAttach:
|
case *frames.PerformAttach:
|
||||||
// On Attach response link should be looked up by name, then added
|
// On Attach response link should be looked up by name, then added
|
||||||
// to the links map with the remote's handle contained in this
|
// to the links map with the remote's handle contained in this
|
||||||
// attach frame.
|
// attach frame.
|
||||||
|
@ -336,9 +337,9 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
link.remoteHandle = body.Handle
|
link.remoteHandle = body.Handle
|
||||||
links[link.remoteHandle] = link
|
links[link.remoteHandle] = link
|
||||||
|
|
||||||
s.muxFrameToLink(link, fr.body)
|
s.muxFrameToLink(link, fr.Body)
|
||||||
|
|
||||||
case *performTransfer:
|
case *frames.PerformTransfer:
|
||||||
// "Upon receiving a transfer, the receiving endpoint will
|
// "Upon receiving a transfer, the receiving endpoint will
|
||||||
// increment the next-incoming-id to match the implicit
|
// increment the next-incoming-id to match the implicit
|
||||||
// transfer-id of the incoming transfer plus one, as well
|
// transfer-id of the incoming transfer plus one, as well
|
||||||
|
@ -356,7 +357,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-s.conn.done:
|
case <-s.conn.done:
|
||||||
case link.rx <- fr.body:
|
case link.rx <- fr.Body:
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this message is received unsettled and link rcv-settle-mode == second, add to handlesByRemoteDeliveryID
|
// if this message is received unsettled and link rcv-settle-mode == second, add to handlesByRemoteDeliveryID
|
||||||
|
@ -369,7 +370,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
// Update peer's outgoing window if half has been consumed.
|
// Update peer's outgoing window if half has been consumed.
|
||||||
if remoteOutgoingWindow < s.incomingWindow/2 {
|
if remoteOutgoingWindow < s.incomingWindow/2 {
|
||||||
nID := nextIncomingID
|
nID := nextIncomingID
|
||||||
flow := &performFlow{
|
flow := &frames.PerformFlow{
|
||||||
NextIncomingID: &nID,
|
NextIncomingID: &nID,
|
||||||
IncomingWindow: s.incomingWindow,
|
IncomingWindow: s.incomingWindow,
|
||||||
NextOutgoingID: nextOutgoingID,
|
NextOutgoingID: nextOutgoingID,
|
||||||
|
@ -379,15 +380,15 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
_ = s.txFrame(flow, nil)
|
_ = s.txFrame(flow, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *performDetach:
|
case *frames.PerformDetach:
|
||||||
link, ok := links[body.Handle]
|
link, ok := links[body.Handle]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.muxFrameToLink(link, fr.body)
|
s.muxFrameToLink(link, fr.Body)
|
||||||
|
|
||||||
case *performEnd:
|
case *frames.PerformEnd:
|
||||||
_ = s.txFrame(&performEnd{}, nil)
|
_ = s.txFrame(&frames.PerformEnd{}, nil)
|
||||||
s.err = fmt.Errorf("session ended by server: %s", body.Error)
|
s.err = fmt.Errorf("session ended by server: %s", body.Error)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -420,13 +421,13 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
|
|
||||||
// if not settled, add done chan to map
|
// if not settled, add done chan to map
|
||||||
// and clear from frame so conn doesn't close it.
|
// and clear from frame so conn doesn't close it.
|
||||||
if !fr.Settled && fr.done != nil {
|
if !fr.Settled && fr.Done != nil {
|
||||||
settlementByDeliveryID[deliveryID] = fr.done
|
settlementByDeliveryID[deliveryID] = fr.Done
|
||||||
fr.done = nil
|
fr.Done = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(2, "TX(Session) - txtransfer: %s", fr)
|
debug(2, "TX(Session) - txtransfer: %s", fr)
|
||||||
_ = s.txFrame(fr, fr.done)
|
_ = s.txFrame(fr, fr.Done)
|
||||||
|
|
||||||
// "Upon sending a transfer, the sending endpoint will increment
|
// "Upon sending a transfer, the sending endpoint will increment
|
||||||
// its next-outgoing-id, decrement its remote-incoming-window,
|
// its next-outgoing-id, decrement its remote-incoming-window,
|
||||||
|
@ -439,7 +440,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
|
|
||||||
case fr := <-s.tx:
|
case fr := <-s.tx:
|
||||||
switch fr := fr.(type) {
|
switch fr := fr.(type) {
|
||||||
case *performFlow:
|
case *frames.PerformFlow:
|
||||||
niID := nextIncomingID
|
niID := nextIncomingID
|
||||||
fr.NextIncomingID = &niID
|
fr.NextIncomingID = &niID
|
||||||
fr.IncomingWindow = s.incomingWindow
|
fr.IncomingWindow = s.incomingWindow
|
||||||
|
@ -447,7 +448,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
fr.OutgoingWindow = s.outgoingWindow
|
fr.OutgoingWindow = s.outgoingWindow
|
||||||
debug(1, "TX(Session) - tx: %s", fr)
|
debug(1, "TX(Session) - tx: %s", fr)
|
||||||
_ = s.txFrame(fr, nil)
|
_ = s.txFrame(fr, nil)
|
||||||
case *performTransfer:
|
case *frames.PerformTransfer:
|
||||||
panic("transfer frames must use txTransfer")
|
panic("transfer frames must use txTransfer")
|
||||||
default:
|
default:
|
||||||
debug(1, "TX(Session) - default: %s", fr)
|
debug(1, "TX(Session) - default: %s", fr)
|
||||||
|
@ -457,7 +458,7 @@ func (s *Session) mux(remoteBegin *performBegin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) muxFrameToLink(l *link, fr frameBody) {
|
func (s *Session) muxFrameToLink(l *link, fr frames.FrameBody) {
|
||||||
select {
|
select {
|
||||||
case l.rx <- fr:
|
case l.rx <- fr:
|
||||||
case <-l.detached:
|
case <-l.detached:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче