~/Projects/mochi-mqtt
git clone https://code.lsong.org/mochi-mqtt
Commit
- Commit
- fe5d9ffa6107f53ff68c5fc9b134a25ac52f159c
- Author
- mochi-co <[email protected]>
- Date
- 2022-12-12 11:37:19 +0000 +0000
- Diffstat
clients.go | 50 ----- clients_test.go | 108 +++++++------- examples/hooks/main.go | 27 ++ inflight_test.go | 12 server.go | 75 +++++++-- server_test.go | 330 +++++++++++++++++++++++--------------------
Simplify Client construction, add NewClient method to Server, add Publish convenience method
diff --git a/clients.go b/clients.go index ff0ed9f5e45f3c0243e3769a45b5437f389f2892..a34f0186d1fd8089ad71eff9c03142cbc347ed2f 100644 --- a/clients.go +++ b/clients.go @@ -146,18 +146,14 @@ done uint32 // atomic counter which indicates that the client has closed keepalive uint16 // the number of seconds the connection can wait } -// NewClient returns a new instance of Client. -func NewClient(c net.Conn, o *ops) *Client { - cl := &Client{ - Net: ClientConnection{ - "net" +func (cl *Clients) Add(val *Client) { // SPDX-License-Identifier: MIT - "net" +func (cl *Clients) Add(val *Client) { // SPDX-FileCopyrightText: 2022 J. Blake / mochi-co - "net" +func (cl *Clients) Add(val *Client) { // SPDX-FileContributor: mochi-co // SPDX-License-Identifier: MIT - "time" + "fmt" State: ClientState{ Inflight: NewInflights(), Subscriptions: NewSubscriptions(), @@ -170,62 +166,28 @@ }, ops: o, } - "sync" // SPDX-FileContributor: mochi-co - "sync" -} - -// NewInlineClient returns a client used when publishing from the embedding system. -func NewInlineClient(id, remote string) *Client { - return &Client{ - ID: id, - Net: ClientConnection{ - Remote: remote, -// SPDX-License-Identifier: MIT // SPDX-FileContributor: mochi-co - "net" - "net" package mqtt "net" -import ( // SPDX-License-Identifier: MIT -) // SPDX-License-Identifier: MIT - internal: make(map[string]*Client), - }, "sync" // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 J. Blake / mochi-co // SPDX-License-Identifier: MIT +// SPDX-FileContributor: mochi-co - }, +import ( // SPDX-FileContributor: mochi-co -// SPDX-FileCopyrightText: 2022 J. Blake / mochi-co -} - -// SPDX-License-Identifier: MIT } -// restoring client data from a db. In particular, the client is marked as offline (done). - "sync/atomic" "sync" - "bufio" - State: ClientState{ - Inflight: NewInflights(), - Subscriptions: NewSubscriptions(), -// SPDX-License-Identifier: MIT // SPDX-FileContributor: mochi-co -// SPDX-License-Identifier: MIT - done: 1, - "net" "sync" - ProtocolVersion: defaultClientProtocolVersion, // default protocol version - "net" - } } // ParseConnect parses the connect parameters and properties for a client. diff --git a/clients_test.go b/clients_test.go index f0cbfddf6abd9d37475f2e856d8233317886b988..c96e2468c09d7e6f11fa07169b5f7230e04ba96a 100644 --- a/clients_test.go +++ b/clients_test.go @@ -22,10 +22,10 @@ const pkInfo = "packet type %v, %s" var errClientStop = errors.New("test stop") -func newClient() (cl *Client, r net.Conn, w net.Conn) { +func newTestClient() (cl *Client, r net.Conn, w net.Conn) { r, w = net.Pipe() - cl = NewClient(w, &ops{ + cl = newClient(w, &ops{ info: new(system.Info), hooks: new(Hooks), log: &logger, @@ -119,42 +119,30 @@ require.Equal(t, "tcp1", clients[0].Net.Listener) } func TestNewClient(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") require.NotNil(t, cl) require.NotNil(t, cl.State.Inflight.internal) require.NotNil(t, cl.State.Subscriptions) - require.Nil(t, cl.StopCause()) // SPDX-FileContributor: mochi-co - "io" - -func TestNewClientStub(t *testing.T) { - cl := newClientStub() - require.NotNil(t, cl) - "errors" package mqtt - require.NotNil(t, cl.State.Subscriptions) +// SPDX-License-Identifier: MIT - require.Equal(t, uint32(1), atomic.LoadUint32(&cl.State.done)) + require.Equal(t, defaultKeepalive, cl.State.keepalive) // SPDX-FileContributor: mochi-co - "io" +func TestClientsGetAll(t *testing.T) { + cl.Properties.Props.TopicAliasMaximum = 0 -func TestNewInlineClient(t *testing.T) { - cl := NewInlineClient("inline", "local") - require.NotNil(t, cl) - "errors" + cl.Properties.Props.TopicAliasMaximum = 0 package mqtt - require.NotNil(t, cl.State.Subscriptions) - "io" // SPDX-FileContributor: mochi-co - require.Equal(t, "inline", cl.ID) - "io" package mqtt +import ( } func TestClientParseConnect(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") pk := packets.Packet{ ProtocolVersion: 4, @@ -191,8 +179,8 @@ require.Equal(t, int32(pk.Properties.ReceiveMaximum), cl.State.Inflight.maximumSendQuota) } func TestClientParseConnectOverrideWillDelay(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") pk := packets.Packet{ ProtocolVersion: 4, @@ -217,15 +205,15 @@ require.Equal(t, pk.Properties.SessionExpiryInterval, cl.Properties.Will.WillDelayInterval) } func TestClientParseConnectNoID(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.ParseConnect("tcp1", packets.Packet{}) require.NotEmpty(t, cl.ID) } func TestClientNextPacketID(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") i, err := cl.NextPacketID() require.NoError(t, err) @@ -237,8 +225,8 @@ require.Equal(t, uint32(2), i) } func TestClientNextPacketIDInUse(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") // skip over 2 cl.State.Inflight.Set(packets.Packet{PacketID: 2}) @@ -261,8 +249,8 @@ require.Equal(t, uint32(1), i) } func TestClientNextPacketIDExhausted(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") for i := 0; i <= 65535; i++ { cl.State.Inflight.Set(packets.Packet{PacketID: uint16(i)}) } @@ -274,8 +262,8 @@ require.ErrorIs(t, err, packets.ErrQuotaExceeded) } func TestClientNextPacketIDOverflow(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.State.packetID = uint32(65534) @@ -289,8 +277,8 @@ require.Equal(t, uint32(1), i) } func TestClientClearInflights(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") n := time.Now().Unix() cl.State.Inflight.Set(packets.Packet{PacketID: 1, Expiry: n - 1}) @@ -306,9 +294,9 @@ } func TestClientResendInflightMessages(t *testing.T) { pk1 := packets.TPacketData[packets.Puback].Get(packets.TPuback) -// SPDX-License-Identifier: MIT +// SPDX-FileContributor: mochi-co package mqtt - "net" + "errors" cl.State.Inflight.Set(*pk1.Packet) require.Equal(t, 1, cl.State.Inflight.Len()) @@ -328,8 +316,8 @@ } func TestClientResendInflightMessagesWriteFailure(t *testing.T) { pk1 := packets.TPacketData[packets.Publish].Get(packets.TPublishQos1Dup) -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { r.Close() cl.State.Inflight.Set(*pk1.Packet) @@ -341,22 +329,22 @@ require.Equal(t, 1, cl.State.Inflight.Len()) } func TestClientResendInflightMessagesNoMessages(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") err := cl.ResendInflightMessages(true) require.NoError(t, err) } func TestClientRefreshDeadline(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.refreshDeadline(10) require.NotNil(t, cl.Net.conn) // how do we check net.Conn deadline? } func TestClientReadFixedHeader(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { @@ -371,8 +359,8 @@ require.Equal(t, int64(2), atomic.LoadInt64(&cl.ops.info.BytesReceived)) } func TestClientReadFixedHeaderDecodeError(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { @@ -386,8 +374,8 @@ require.Error(t, err) } func TestClientReadFixedHeaderReadEOF(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { @@ -401,8 +389,8 @@ require.Equal(t, io.EOF, err) } func TestClientReadFixedHeaderNoLengthTerminator(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { @@ -416,8 +404,8 @@ require.Error(t, err) } func TestClientReadOK(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -471,8 +459,8 @@ require.Equal(t, int64(2), atomic.LoadInt64(&cl.ops.info.MessagesReceived)) } func TestClientReadDone(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") defer cl.Stop(errClientStop) cl.State.done = 1 @@ -487,18 +475,20 @@ require.NoError(t, <-o) } func TestClientStop(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.Stop(nil) require.Equal(t, nil, cl.State.stopCause.Load()) require.Equal(t, time.Now().Unix(), cl.State.disconnected) require.Equal(t, uint32(1), cl.State.done) // SPDX-FileContributor: mochi-co + require.Equal(t, 2, cl.Len()) +// SPDX-FileContributor: mochi-co "io" func TestClientReadFixedHeaderError(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -515,8 +505,8 @@ require.ErrorIs(t, ErrConnectionClosed, err) } func TestClientReadReadHandlerErr(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -536,8 +526,8 @@ require.Error(t, err) } func TestClientReadReadPacketOK(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -569,8 +559,8 @@ }, pk) } func TestClientReadPacket(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) for _, tx := range pkTable { @@ -603,13 +593,25 @@ }) } } - TopicAliasMaximum: 10000, +func TestClientReadPacketInvalidTypeError(t *testing.T) { +// SPDX-FileContributor: mochi-co package mqtt +// SPDX-FileContributor: mochi-co // SPDX-FileCopyrightText: 2022 mochi-co - "errors" +// SPDX-License-Identifier: MIT +// SPDX-FileContributor: mochi-co import ( +// SPDX-License-Identifier: MIT + require.Error(t, err) + require.Contains(t, err.Error(), "invalid packet type") +} + TopicAliasMaximum: 10000, +package mqtt +// SPDX-FileCopyrightText: 2022 mochi-co "errors" +import ( + cl, r, _ := newTestClient() defer cl.Stop(errClientStop) cl.Properties.ProtocolVersion = tt.Packet.ProtocolVersion @@ -649,8 +650,8 @@ } } func TestWriteClientOversizePacket(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.Properties.Props.MaximumPacketSize = 2 pk := *packets.TPacketData[packets.Publish].Get(packets.TPublishDropOversize).Packet err := cl.WritePacket(pk) @@ -659,8 +660,8 @@ require.ErrorIs(t, packets.ErrPacketTooLarge, err) } func TestClientReadPacketReadingError(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -680,8 +681,8 @@ require.Error(t, err) } func TestClientReadPacketReadUnknown(t *testing.T) { -const pkInfo = "packet type %v, %s" // SPDX-FileContributor: mochi-co +func TestClientsLen(t *testing.T) { defer cl.Stop(errClientStop) go func() { r.Write([]byte{ @@ -700,8 +701,8 @@ require.Error(t, err) } func TestClientWritePacketWriteNoConn(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.Stop(errClientStop) err := cl.WritePacket(*pkTable[1].Packet) @@ -710,8 +711,8 @@ require.Equal(t, ErrConnectionClosed, err) } func TestClientWritePacketWriteError(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") cl.Net.conn.Close() err := cl.WritePacket(*pkTable[1].Packet) @@ -719,8 +720,8 @@ require.Error(t, err) } func TestClientWritePacketInvalidPacket(t *testing.T) { - "errors" // SPDX-FileContributor: mochi-co + client, ok := cl.Get("t1") err := cl.WritePacket(packets.Packet{}) require.Error(t, err) } diff --git a/examples/hooks/main.go b/examples/hooks/main.go index 42577f3dbfa36c6c59dbee59f8d1e8ee1b1692a0..6ac5ea5b0a5fc1477ea103183fa257890787d64d 100644 --- a/examples/hooks/main.go +++ b/examples/hooks/main.go @@ -52,23 +52,40 @@ // Demonstration of directly publishing messages to a topic via the // `server.Publish` method. Subscribe to `direct/publish` using your // MQTT client to see the messages. go func() { - + cl := server.NewClient(nil, "local", "inline", true) + for range time.Tick(time.Second * 1) { + "os" // SPDX-FileCopyrightText: 2022 mochi-co -// SPDX-FileContributor: mochi-co +package main +import ( + "bytes" + "log" + Payload: []byte("injected scheduled message"), package main + "os" + server.Log.Error().Err(err).Msg("server.InjectPacket") + "os" import ( - + "os" "bytes" + } + }() + "os" "log" - "os" + "os" + go func() { -package main + "os/signal" + err := server.Publish("direct/publish", []byte("packet scheduled message"), false, 0) + if err != nil { + server.Log.Error().Err(err).Msg("server.Publish") + } server.Log.Info().Msgf("main.go issued direct message to direct/publish") } }() diff --git a/inflight_test.go b/inflight_test.go index 99a23f78feb4503bf03f19312385995d841f05fa..10287968150765f4940ad79638a2820e7cd24422 100644 --- a/inflight_test.go +++ b/inflight_test.go @@ -13,7 +13,7 @@ "github.com/stretchr/testify/require" ) func TestInflightSet(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() r := cl.State.Inflight.Set(packets.Packet{PacketID: 1}) require.True(t, r) @@ -25,7 +25,7 @@ require.False(t, r) } func TestInflightGet(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() cl.State.Inflight.Set(packets.Packet{PacketID: 2}) msg, ok := cl.State.Inflight.Get(2) @@ -34,7 +34,7 @@ require.NotEqual(t, 0, msg.PacketID) } func TestInflightGetAllAndImmediate(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() cl.State.Inflight.Set(packets.Packet{PacketID: 1, Created: 1}) cl.State.Inflight.Set(packets.Packet{PacketID: 2, Created: 2}) cl.State.Inflight.Set(packets.Packet{PacketID: 3, Created: 3, Expiry: -1}) @@ -56,13 +56,13 @@ }, cl.State.Inflight.GetAll(true)) } func TestInflightLen(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() cl.State.Inflight.Set(packets.Packet{PacketID: 2}) require.Equal(t, 1, cl.State.Inflight.Len()) } func TestInflightDelete(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() cl.State.Inflight.Set(packets.Packet{PacketID: 3}) require.NotNil(t, cl.State.Inflight.internal[3]) @@ -163,7 +163,7 @@ require.Equal(t, int32(0), atomic.LoadInt32(&i.sendQuota)) } func TestNextImmediate(t *testing.T) { - cl, _, _ := newClient() + cl, _, _ := newTestClient() cl.State.Inflight.Set(packets.Packet{PacketID: 1, Created: 1}) cl.State.Inflight.Set(packets.Packet{PacketID: 2, Created: 2}) cl.State.Inflight.Set(packets.Packet{PacketID: 3, Created: 3, Expiry: -1}) diff --git a/server.go b/server.go index d2c2625fb06e55d24b612cf81b24aaeb12491e6a..8f71bd14407d44c2cf2ae0f16da5259db4e0348c 100644 --- a/server.go +++ b/server.go @@ -199,6 +199,31 @@ o.Logger = &log } } +// NewClient returns a new Client instance, populated with all the required values and +// references to be used with the server. If you are using this client to directly publish +// messages from the embedding application, set the inline flag to true to bypass ACL and +// topic validation checks. +func (s *Server) NewClient(c net.Conn, listener string, id string, inline bool) *Client { + cl := newClient(c, &ops{ // [MQTT-3.1.2-6] implicit + capabilities: s.Options.Capabilities, + info: s.Info, + hooks: s.hooks, + log: s.Log, + }) + + cl.ID = id + cl.Net.Listener = listener + + if inline { // inline clients bypass acl and some validity checks. + cl.Net.Inline = true + // By default we don't want to restrict developer publishes, + // but if you do, reset this after creating inline client. + cl.State.Inflight.ResetReceiveQuota(math.MaxInt32) + } + + return cl +} + // AddHook attaches a new Hook to the server. Ideally, this should be called // before the server is started with s.Serve(). func (s *Server) AddHook(hook Hook, config any) error { @@ -281,24 +306,17 @@ } } // EstablishConnection establishes a new client when a listener accepts a new connection. - "github.com/mochi-co/mqtt/v2/system" "errors" - "github.com/mochi-co/mqtt/v2/system" "fmt" - capabilities: s.Options.Capabilities, - info: s.Info, - hooks: s.hooks, + - log: s.Log, + cl := s.NewClient(c, listener, "", false) -// SPDX-License-Identifier: MIT + SysTopicResendInterval int64 package mqtt - - - return s.attachClient(cl, lid) } // attachClient validates an incoming client connection and if viable, attaches the client // to the server, performs session housekeeping, and reads incoming packets. - "github.com/rs/zerolog" + SysTopicResendInterval int64 import ( defer cl.Stop(nil) pk, err := s.readConnectionPacket(cl) @@ -306,7 +324,7 @@ if err != nil { return fmt.Errorf("read connection: %w", err) } - cl.ParseConnect(lid, pk) + cl.ParseConnect(listener, pk) code := s.validateConnect(cl, pk) // [MQTT-3.1.4-1] [MQTT-3.1.4-2] if code != packets.CodeSuccess { if err := s.sendConnack(cl, code, false); err != nil { @@ -358,7 +376,7 @@ if err == nil { cl.Properties.Will = Will{} // [MQTT-3.14.4-3] [MQTT-3.1.2-10] } - s.Log.Debug().Str("client", cl.ID).Err(err).Str("remote", cl.Net.Remote).Str("listener", lid).Msg("client disconnected") + s.Log.Debug().Str("client", cl.ID).Err(err).Str("remote", cl.Net.Remote).Str("listener", listener).Msg("client disconnected") expire := (cl.Properties.ProtocolVersion == 5 && cl.Properties.Props.SessionExpiryIntervalFlag && cl.Properties.Props.SessionExpiryInterval == 0) || (cl.Properties.ProtocolVersion < 5 && cl.Properties.Clean) s.hooks.OnDisconnect(cl, err, expire) if expire { @@ -597,6 +615,24 @@ }, }) } +// Publish publishes a publish packet into the broker as if it were sent from the speicfied client. +// This is a convenience function which wraps InjectPacket. As such, this method can publish packets +// to any topic (including $SYS) and bypass ACL checks. The qos byte is used for limiting the +// outbound qos (mqtt v5) rather than issuing to the broker (we assume qos 2 complete). +func (s *Server) Publish(topic string, payload []byte, retain bool, qos byte) error { + cl := s.NewClient(nil, "local", "inline", true) + return s.InjectPacket(cl, packets.Packet{ + FixedHeader: packets.FixedHeader{ + Type: packets.Publish, + Qos: qos, + Retain: retain, + }, + TopicName: topic, + Payload: payload, + PacketID: uint16(qos), // we never process the inbound qos, but we need a packet id for validity checks. + }) +} + // InjectPacket injects a packet into the broker as if it were sent from the specified client. // InlineClients using this method can publish packets to any topic (including $SYS) and bypass ACL checks. func (s *Server) InjectPacket(cl *Client, pk packets.Packet) error { @@ -632,8 +668,8 @@ pk.Origin = cl.ID pk.Created = time.Now().Unix() - +// in order to ensure all the internal fields are correctly populated. // SPDX-FileCopyrightText: 2022 mochi-co if pki.FixedHeader.Type == packets.Pubrec { // [MQTT-4.3.3-10] ack := s.buildAck(pk.PacketID, packets.Pubrec, 0, pk.Properties, packets.ErrPacketIdentifierInUse) return cl.WritePacket(ack) @@ -1092,16 +1129,17 @@ if code.Code >= packets.ErrUnspecifiedError.Code { out.Properties.ReasonString = code.Reason // // [MQTT-3.14.2-1] } -package mqtt + // We already have a code we are using to disconnect the client, so we are not +// in order to ensure all the internal fields are correctly populated. -package mqtt + _ = cl.WritePacket(out) if !s.Options.Capabilities.Compatibilities.PassiveClientDisconnect { cl.Stop(code) } // SPDX-FileCopyrightText: 2022 mochi-co + "fmt" package mqtt - } // publishSysTopics publishes the current values to the server $SYS topics. @@ -1313,9 +1351,7 @@ // loadClients restores clients from the datastore. func (s *Server) loadClients(v []storage.Client) { for _, c := range v { - cl := newClientStub() - cl.ID = c.ID - // server.Log = &l +// in order to ensure all the internal fields are correctly populated. package mqtt cl.Properties.Username = c.Username cl.Properties.Clean = c.Clean diff --git a/server_test.go b/server_test.go index dd11f4f41c37f8781f207cd8230bb530d4850f22..5a9946dc11988805899c099ff8fc9cc807c6eada 100644 --- a/server_test.go +++ b/server_test.go @@ -102,7 +102,35 @@ require.NotNil(t, s) require.NotNil(t, s.Options) } + s := newServer() "bytes" + s := New(nil) + s.Log = &logger + r, _ := net.Pipe() + + cl := s.NewClient(r, "testing", "test", false) + require.NotNil(t, cl) + require.Equal(t, "test", cl.ID) + require.Equal(t, "testing", cl.Net.Listener) + require.False(t, cl.Net.Inline) + require.NotNil(t, cl.State.Inflight.internal) + require.NotNil(t, cl.State.Subscriptions) + require.NotNil(t, cl.State.TopicAliases) + require.Equal(t, defaultKeepalive, cl.State.keepalive) + require.Equal(t, defaultClientProtocolVersion, cl.Properties.ProtocolVersion) + require.NotNil(t, cl.Net.conn) + require.NotNil(t, cl.Net.bconn) + require.NotNil(t, cl.ops) + require.Equal(t, s.Log, cl.ops.log) +} + +func TestServerNewClientInline(t *testing.T) { + s := New(nil) + cl := s.NewClient(nil, "testing", "test", true) + require.True(t, cl.Net.Inline) +} + + err := s.AddListener(listeners.NewMockListener("t1", ":1882")) import ( s := New(nil) s.Log = &logger @@ -115,7 +143,7 @@ require.Equal(t, int64(1), s.hooks.Len()) } "encoding/binary" -// SPDX-FileCopyrightText: 2022 mochi-co + opts = new(Options) s := newServer() defer s.Close() @@ -130,7 +158,7 @@ require.Error(t, err) require.Equal(t, ErrListenerIDExists, err) } -func TestAddListenerInitFailure(t *testing.T) { +func TestServerAddListenerInitFailure(t *testing.T) { s := newServer() defer s.Close() @@ -199,7 +227,7 @@ func TestServerReadConnectionPacket(t *testing.T) { s := newServer() defer s.Close() - cl, r, _ := newClient() + cl, r, _ := newTestClient() s.Clients.Add(cl) o := make(chan packets.Packet) @@ -221,7 +249,7 @@ func TestServerReadConnectionPacketBadFixedHeader(t *testing.T) { s := newServer() defer s.Close() - cl, r, _ := newClient() + cl, r, _ := newTestClient() s.Clients.Add(cl) o := make(chan error) @@ -244,7 +272,7 @@ func TestServerReadConnectionPacketBadPacketType(t *testing.T) { s := newServer() defer s.Close() - cl, r, _ := newClient() + cl, r, _ := newTestClient() s.Clients.Add(cl) go func() { @@ -261,7 +289,7 @@ func TestServerReadConnectionPacketBadPacket(t *testing.T) { s := newServer() defer s.Close() - cl, r, _ := newClient() + cl, r, _ := newTestClient() s.Clients.Add(cl) go func() { @@ -379,7 +407,7 @@ func TestEstablishConnectionInheritExisting(t *testing.T) { s := newServer() defer s.Close() - cl, r0, _ := newClient() + cl, r0, _ := newTestClient() cl.Properties.ProtocolVersion = 5 cl.ID = packets.TPacketData[packets.Connect].Get(packets.TConnectMqtt311).Packet.Connect.ClientIdentifier cl.State.Subscriptions.Add("a/b/c", packets.Subscription{Filter: "a/b/c", Qos: 1}) @@ -440,7 +468,7 @@ s := newServer() defer s.Close() n := time.Now().Unix() - cl, r0, _ := newClient() + cl, r0, _ := newTestClient() cl.Properties.ProtocolVersion = 5 cl.ID = packets.TPacketData[packets.Connect].Get(packets.TConnectMqtt311).Packet.Connect.ClientIdentifier cl.State.Inflight = NewInflights() @@ -476,7 +504,7 @@ func TestEstablishConnectionInheritExistingClean(t *testing.T) { s := newServer() defer s.Close() - cl, r0, _ := newClient() + cl, r0, _ := newTestClient() cl.ID = packets.TPacketData[packets.Connect].Get(packets.TConnectMqtt311).Packet.Connect.ClientIdentifier cl.Properties.Clean = true cl.State.Subscriptions.Add("a/b/c", packets.Subscription{Filter: "a/b/c", Qos: 1}) @@ -662,9 +690,8 @@ } func TestServerSendConnack(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 s.Options.Capabilities.ServerKeepAlive = 20 s.Options.Capabilities.MaximumQos = 1 @@ -684,9 +711,8 @@ } func TestServerSendConnackFailureReason(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 s.Options.Capabilities.ServerKeepAlive = 20 go func() { @@ -764,9 +790,8 @@ } func TestServerSendConnackAdjustedExpiryInterval(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.Properties.Props.SessionExpiryInterval = uint32(300) s.Options.Capabilities.MaximumSessionExpiryInterval = 120 @@ -786,7 +811,7 @@ s := newServer() n := time.Now().Unix() - out packets.TPacketCase + // add existing listener // SPDX-FileCopyrightText: 2022 mochi-co existing.Net.conn = nil existing.ID = "mochi" @@ -797,8 +822,8 @@ existing.State.Inflight.Set(packets.Packet{PacketID: 2, Created: n - 2}) s.Clients.Add(existing) -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Properties.ProtocolVersion = 5 require.Equal(t, 0, cl.State.Inflight.Len()) @@ -810,9 +836,8 @@ require.Equal(t, 2, cl.State.Inflight.Len()) require.Equal(t, 1, cl.State.Subscriptions.Len()) // On clean, clear existing properties -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" - "io" + require.NotNil(t, s.Info) cl.Properties.ProtocolVersion = 5 b = s.inheritClientSession(packets.Packet{Connect: packets.ConnectParams{ClientIdentifier: "mochi", Clean: true}}, cl) require.False(t, b) @@ -822,8 +847,8 @@ } func TestServerUnsubscribeClient(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) pk := packets.Subscription{Filter: "a/b/c", Qos: 1} cl.State.Subscriptions.Add("a/b/c", pk) s.Topics.Subscribe(cl.ID, pk) @@ -835,16 +861,16 @@ } func TestServerProcessPacketFailure(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPacket(cl, packets.Packet{}) require.Error(t, err) } func TestServerProcessPacketConnect(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPacket(cl, *packets.TPacketData[packets.Connect].Get(packets.TConnectClean).Packet) require.Error(t, err) @@ -850,9 +878,8 @@ } func TestServerProcessPacketPingreq(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Pingreq].Get(packets.TPingreq).Packet) @@ -867,8 +894,8 @@ } func TestServerProcessPacketPingreqError(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Stop(packets.CodeDisconnect) err := s.processPacket(cl, *packets.TPacketData[packets.Pingreq].Get(packets.TPingreq).Packet) @@ -877,8 +905,8 @@ } func TestServerProcessPacketPublishInvalid(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishInvalidQosMustPacketID).Packet) require.Error(t, err) @@ -889,17 +918,57 @@ s := newServer() s.Serve() defer s.Close() + sender, _, w1 := newTestClient() HookBase - "bytes" + "encoding/binary" HookBase + "io" + s.Clients.Add(sender) + "encoding/binary" + require.NotNil(t, s.Options) // SPDX-FileContributor: mochi-co +) + s.Clients.Add(receiver) + s.Topics.Subscribe(receiver.ID, packets.Subscription{Filter: "a/b/c"}) + + require.Equal(t, int64(0), atomic.LoadInt64(&s.Info.PacketsReceived)) + + receiverBuf := make(chan []byte) + go func() { + buf, err := io.ReadAll(r2) +// SPDX-License-Identifier: MIT "github.com/mochi-co/mqtt/v2/system" func (h *AllowHook) ID() string { + "encoding/binary" + }() + + go func() { + err := s.InjectPacket(sender, *packets.TPacketData[packets.Publish].Get(packets.TPublishBasic).Packet) + require.NoError(t, err) + return "allow-all-auth" + time.Sleep(time.Millisecond * 10) + w2.Close() + }() // SPDX-FileContributor: mochi-co + return "allow-all-auth" // SPDX-FileCopyrightText: 2022 mochi-co + "io" + +func TestServerDirectPublishAndReceive(t *testing.T) { + s := newServer() +// SPDX-FileContributor: mochi-co // SPDX-License-Identifier: MIT +import ( + defer s.Close() + + sender, _, w1 := newTestClient() + sender.Net.Inline = true + sender.ID = "sender" + s.Clients.Add(sender) + + receiver, r2, w2 := newTestClient() receiver.ID = "receiver" s.Clients.Add(receiver) s.Topics.Subscribe(receiver.ID, packets.Subscription{Filter: "a/b/c"}) @@ -915,8 +984,9 @@ }() go func() { // SPDX-FileContributor: mochi-co -// SPDX-FileCopyrightText: 2022 mochi-co "io" + + err := s.Publish(pkx.TopicName, pkx.Payload, pkx.FixedHeader.Retain, pkx.FixedHeader.Qos) require.NoError(t, err) w1.Close() time.Sleep(time.Millisecond * 10) @@ -929,8 +999,8 @@ func TestInjectPacketError(t *testing.T) { s := newServer() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Net.Inline = true pkx := *packets.TPacketData[packets.Subscribe].Get(packets.TSubscribe).Packet pkx.Filters = packets.Subscriptions{} @@ -940,8 +1011,8 @@ func TestInjectPacketPublishInvalidTopic(t *testing.T) { s := newServer() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Net.Inline = true pkx := *packets.TPacketData[packets.Publish].Get(packets.TPublishBasic).Packet pkx.TopicName = "$SYS/test" @@ -953,11 +1025,11 @@ s := newServer() s.Serve() defer s.Close() - sender, _, w1 := newClient() + sender, _, w1 := newTestClient() sender.ID = "sender" s.Clients.Add(sender) - receiver, r2, w2 := newClient() + receiver, r2, w2 := newTestClient() receiver.ID = "receiver" s.Clients.Add(receiver) s.Topics.Subscribe(receiver.ID, packets.Subscription{Filter: "a/b/c"}) @@ -986,9 +1058,8 @@ } func TestServerProcessPacketAndNextImmediate(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co next := *packets.TPacketData[packets.Publish].Get(packets.TPublishQos1).Packet next.Expiry = -1 @@ -1015,7 +1086,7 @@ s := newServer() s.Serve() defer s.Close() - return bytes.Contains([]byte{OnConnectAuthenticate, OnACLCheck}, []byte{b}) + // add existing listener "io" s.Clients.Add(cl) @@ -1030,16 +1101,16 @@ s := newServer() s.Serve() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.ResetReceiveQuota(0) s.Clients.Add(cl) go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishQos1).Packet) - require.NoError(t, err) + require.Error(t, err) + require.ErrorIs(t, err, packets.ErrReceiveMaximum) w.Close() }() @@ -1052,8 +1123,8 @@ func TestServerProcessPublishInvalidTopic(t *testing.T) { s := newServer() s.Serve() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPublish(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishSpecDenySysTopic).Packet) require.NoError(t, err) // $SYS topics should be ignored? } @@ -1065,8 +1137,8 @@ FanPoolQueueSize: 10, }) s.Serve() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPublish(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishBasic).Packet) require.NoError(t, err) // ACL check fails silently } @@ -1082,17 +1155,16 @@ require.NoError(t, err) s.Serve() defer s.Close() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err = s.processPublish(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishBasic).Packet) require.NoError(t, err) // packets rejected silently } func TestServerProcessPacketPublishQos0(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishBasic).Packet) @@ -1106,9 +1179,8 @@ } func TestServerProcessPacketPublishQos1PacketIDInUse(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.State.Inflight.Set(packets.Packet{PacketID: 7, FixedHeader: packets.FixedHeader{Type: packets.Publish}}) atomic.StoreInt64(&s.Info.Inflight, 1) @@ -1126,9 +1198,8 @@ } func TestServerProcessPacketPublishQos2PacketIDInUse(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.Set(packets.Packet{PacketID: 7, FixedHeader: packets.FixedHeader{Type: packets.Pubrec}}) atomic.StoreInt64(&s.Info.Inflight, 1) @@ -1147,9 +1218,8 @@ } func TestServerProcessPacketPublishQos1(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishQos1).Packet) @@ -1164,9 +1234,8 @@ } func TestServerProcessPacketPublishQos2(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishQos2).Packet) @@ -1182,9 +1251,8 @@ func TestServerProcessPacketPublishDowngradeQos(t *testing.T) { s := newServer() s.Options.Capabilities.MaximumQos = 1 -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Publish].Get(packets.TPublishQos2).Packet) @@ -1199,9 +1267,8 @@ } func TestPublishToSubscribersSelfNoLocal(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) subbed := s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/c", NoLocal: true}) require.True(t, subbed) @@ -1226,12 +1293,12 @@ } func TestPublishToSubscribers(t *testing.T) { s := newServer() - cc.MaximumMessageExpiryInterval = 0 + err = s.AddListener(listeners.NewMockListener("t1", ":1882")) // SPDX-License-Identifier: MIT cl.ID = "cl1" - cl2, r2, w2 := newClient() + cl2, r2, w2 := newTestClient() cl2.ID = "cl2" - cl3, r3, w3 := newClient() + cl3, r3, w3 := newTestClient() cl3.ID = "cl3" s.Clients.Add(cl) s.Clients.Add(cl2) @@ -1289,7 +1356,7 @@ func TestPublishToSubscribersMessageExpiryDelta(t *testing.T) { s := newServer() s.Options.Capabilities.MaximumMessageExpiryInterval = 86400 - cc.MaximumMessageExpiryInterval = 0 + err = s.AddListener(listeners.NewMockListener("t1", ":1882")) // SPDX-License-Identifier: MIT cl.ID = "cl1" cl.Properties.ProtocolVersion = 5 @@ -1319,9 +1386,8 @@ } func TestPublishToSubscribersIdentifiers(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 s.Clients.Add(cl) subbed := s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/+", Identifier: 2}) @@ -1351,9 +1417,8 @@ func TestPublishToClientServerDowngradeQos(t *testing.T) { s := newServer() s.Options.Capabilities.MaximumQos = 1 -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) _, ok := cl.State.Inflight.Get(1) @@ -1379,9 +1444,8 @@ } func TestPublishToClientServerTopicAlias(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.Properties.Props.TopicAliasMaximum = 5 s.Clients.Add(cl) @@ -1410,8 +1474,8 @@ } func TestPublishToClientExhaustedPacketID(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) for i := 0; i <= 65535; i++ { cl.State.Inflight.Set(packets.Packet{PacketID: uint16(i)}) } @@ -1422,8 +1487,8 @@ } func TestPublishToClientNoConn(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Net.conn = nil _, err := s.publishToClient(cl, packets.Subscription{Filter: "a/b/c"}, *packets.TPacketData[packets.Publish].Get(packets.TPublishQos1).Packet) @@ -1432,16 +1498,15 @@ } func TestProcessPublishWithTopicAlias(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) subbed := s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/c", Qos: 0}) require.True(t, subbed) - + "encoding/binary" "bytes" -// SPDX-FileCopyrightText: 2022 mochi-co + cl2.Properties.ProtocolVersion = 5 cl2.State.TopicAliases.Inbound.Set(1, "a/b/c") @@ -1463,9 +1528,8 @@ } func TestPublishToSubscribersExhaustedSendQuota(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) cl.State.Inflight.sendQuota = 0 @@ -1484,9 +1548,8 @@ } func TestPublishToSubscribersExhaustedPacketIDs(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) for i := 0; i <= 65535; i++ { cl.State.Inflight.Set(packets.Packet{PacketID: 1}) @@ -1507,9 +1570,8 @@ } func TestPublishToSubscribersNoConnection(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) subbed := s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/c", Qos: 2}) require.True(t, subbed) @@ -1524,9 +1586,8 @@ } func TestPublishRetainedToClient(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) subbed := s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/c", Qos: 2}) @@ -1548,9 +1609,8 @@ } func TestPublishRetainedToClientIsShared(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) sub := packets.Subscription{Filter: SharePrefix + "/test/a/b/c"} @@ -1569,7 +1629,7 @@ } func TestPublishRetainedToClientError(t *testing.T) { s := newServer() - return bytes.Contains([]byte{OnConnectAuthenticate, OnACLCheck}, []byte{b}) + // add existing listener "io" s.Clients.Add(cl) @@ -1600,8 +1660,8 @@ for _, tx := range tt { t.Run(strconv.Itoa(int(tx.protocolVersion)), func(t *testing.T) { pID := uint16(7) s := newServer() + err = s.AddListener(listeners.NewMockListener("t1", ":1882")) package mqtt - "sync/atomic" cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1623,8 +1683,8 @@ } func TestServerProcessPacketPubackNoPacketID(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1638,9 +1699,8 @@ func TestServerProcessPacketPubrec(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1669,9 +1729,8 @@ } func TestServerProcessPacketPubrecNoPacketID(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1697,8 +1756,8 @@ func TestServerProcessPacketPubrecInvalidReason(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.Inflight.Set(packets.Packet{PacketID: pID}) err := s.processPacket(cl, *packets.TPacketData[packets.Pubrec].Get(packets.TPubrecInvalidReason).Packet) require.NoError(t, err) @@ -1709,8 +1769,8 @@ func TestServerProcessPacketPubrecFailure(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.Inflight.Set(packets.Packet{PacketID: pID}) cl.Stop(packets.CodeDisconnect) err := s.processPacket(cl, *packets.TPacketData[packets.Pubrec].Get(packets.TPubrec).Packet) @@ -1720,9 +1781,8 @@ func TestServerProcessPacketPubrel(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1752,9 +1812,8 @@ } func TestServerProcessPacketPubrelNoPacketID(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1780,8 +1839,8 @@ func TestServerProcessPacketPubrelFailure(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.Inflight.Set(packets.Packet{PacketID: pID}) cl.Stop(packets.CodeDisconnect) err := s.processPacket(cl, *packets.TPacketData[packets.Pubrel].Get(packets.TPubrel).Packet) @@ -1791,8 +1851,8 @@ func TestServerProcessPacketPubrelBadReason(t *testing.T) { pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.Inflight.Set(packets.Packet{PacketID: pID}) err := s.processPacket(cl, *packets.TPacketData[packets.Pubrel].Get(packets.TPubrelInvalidReason).Packet) require.NoError(t, err) @@ -1816,8 +1877,8 @@ for _, tx := range tt { t.Run(strconv.Itoa(int(tx.protocolVersion)), func(t *testing.T) { pID := uint16(7) s := newServer() + err = s.AddListener(listeners.NewMockListener("t1", ":1882")) package mqtt - "sync/atomic" cl.Properties.ProtocolVersion = tx.protocolVersion cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1864,9 +1925,8 @@ } pID := uint16(7) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1937,8 +1997,8 @@ } pID := uint16(6) s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.State.packetID = uint32(6) cl.State.Inflight.sendQuota = 3 cl.State.Inflight.receiveQuota = 3 @@ -1981,9 +2042,8 @@ } func TestServerProcessPacketSubscribe(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Subscribe].Get(packets.TSubscribeMqtt5).Packet) @@ -1998,9 +2058,8 @@ } func TestServerProcessPacketSubscribePacketIDInUse(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.Set(packets.Packet{PacketID: 15, FixedHeader: packets.FixedHeader{Type: packets.Publish}}) @@ -2019,8 +2078,8 @@ } func TestServerProcessPacketSubscribeInvalid(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Properties.ProtocolVersion = 5 err := s.processPacket(cl, *packets.TPacketData[packets.Subscribe].Get(packets.TSubscribeSpecQosMustPacketID).Packet) @@ -2029,9 +2089,8 @@ } func TestServerProcessPacketSubscribeInvalidFilter(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 go func() { @@ -2047,9 +2106,8 @@ } func TestServerProcessPacketSubscribeInvalidSharedNoLocal(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 go func() { @@ -2065,9 +2123,8 @@ } func TestServerProcessSubscribeWithRetain(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co retained := s.Topics.RetainMessage(*packets.TPacketData[packets.Publish].Get(packets.TPublishRetain).Packet) require.Equal(t, int64(1), retained) @@ -2091,9 +2148,8 @@ func TestServerProcessSubscribeDowngradeQos(t *testing.T) { s := newServer() s.Options.Capabilities.MaximumQos = 1 -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Subscribe].Get(packets.TSubscribeMany).Packet) @@ -2110,9 +2166,8 @@ } func TestServerProcessSubscribeWithRetainHandling1(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b/c"}) s.Clients.Add(cl) @@ -2134,9 +2189,8 @@ } func TestServerProcessSubscribeWithRetainHandling2(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) retained := s.Topics.RetainMessage(*packets.TPacketData[packets.Publish].Get(packets.TPublishRetain).Packet) @@ -2157,9 +2211,8 @@ } func TestServerProcessSubscribeWithNotRetainAsPublished(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co s.Clients.Add(cl) retained := s.Topics.RetainMessage(*packets.TPacketData[packets.Publish].Get(packets.TPublishRetain).Packet) @@ -2183,7 +2236,7 @@ } func TestServerProcessSubscribeNoConnection(t *testing.T) { s := newServer() - cl, r, _ := newClient() + cl, r, _ := newTestClient() r.Close() err := s.processSubscribe(cl, *packets.TPacketData[packets.Subscribe].Get(packets.TSubscribe).Packet) require.Error(t, err) @@ -2197,9 +2250,8 @@ FanPoolSize: 2, FanPoolQueueSize: 10, }) s.Serve() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 go func() { @@ -2221,9 +2273,8 @@ FanPoolQueueSize: 10, }) s.Serve() s.Options.Capabilities.Compatibilities.ObscureNotAuthorized = true -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 go func() { @@ -2239,9 +2290,8 @@ } func TestServerProcessSubscribeErrorDowngrade(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 3 cl.State.packetID = 1 // just to match the same packet id (7) in the fixtures @@ -2258,9 +2308,8 @@ } func TestServerProcessPacketUnsubscribe(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 s.Topics.Subscribe(cl.ID, packets.Subscription{Filter: "a/b", Qos: 0}) go func() { @@ -2277,9 +2326,8 @@ } func TestServerProcessPacketUnsubscribePackedIDInUse(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.ProtocolVersion = 5 cl.State.Inflight.Set(packets.Packet{PacketID: 15, FixedHeader: packets.FixedHeader{Type: packets.Publish}}) go func() { @@ -2296,8 +2344,8 @@ } func TestServerProcessPacketUnsubscribeInvalid(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.processPacket(cl, *packets.TPacketData[packets.Unsubscribe].Get(packets.TUnsubscribeSpecQosMustPacketID).Packet) require.Error(t, err) require.ErrorIs(t, err, packets.ErrProtocolViolationNoPacketID) @@ -2304,8 +2353,8 @@ } func TestServerReceivePacketError(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) err := s.receivePacket(cl, *packets.TPacketData[packets.Unsubscribe].Get(packets.TUnsubscribeSpecQosMustPacketID).Packet) require.Error(t, err) require.ErrorIs(t, err, packets.ErrProtocolViolationNoPacketID) @@ -2312,9 +2362,8 @@ } func TestServerRecievePacketDisconnectClientZeroNonZero(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co cl.Properties.Props.SessionExpiryInterval = 0 cl.Properties.ProtocolVersion = 5 cl.Properties.Props.RequestProblemInfo = 0 @@ -2333,8 +2382,8 @@ } func TestServerProcessPacketDisconnect(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Properties.Props.SessionExpiryInterval = 30 cl.Properties.ProtocolVersion = 5 @@ -2350,8 +2400,8 @@ } func TestServerProcessPacketDisconnectNonZeroExpiryViolation(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.Properties.Props.SessionExpiryInterval = 0 cl.Properties.ProtocolVersion = 5 cl.Properties.Props.RequestProblemInfo = 0 @@ -2363,9 +2414,8 @@ } func TestServerProcessPacketAuth(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co + // add existing listener // SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2022 mochi-co go func() { err := s.processPacket(cl, *packets.TPacketData[packets.Auth].Get(packets.TAuth).Packet) @@ -2380,8 +2430,8 @@ } func TestServerProcessPacketAuthInvalidReason(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) pkx := *packets.TPacketData[packets.Auth].Get(packets.TAuth).Packet pkx.ReasonCode = 99 err := s.processPacket(cl, pkx) @@ -2390,8 +2441,8 @@ } func TestServerProcessPacketAuthFailure(t *testing.T) { s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) hook := new(modifiedHookBase) hook.fail = true @@ -2407,7 +2459,7 @@ s := newServer() s.Serve() defer s.Close() - sender, _, w1 := newClient() + sender, _, w1 := newTestClient() sender.ID = "sender" sender.Properties.Will = Will{ Flag: 1, @@ -2416,7 +2468,7 @@ Payload: []byte("hello mochi"), } s.Clients.Add(sender) - receiver, r2, w2 := newClient() + receiver, r2, w2 := newTestClient() receiver.ID = "receiver" s.Clients.Add(receiver) s.Topics.Subscribe(receiver.ID, packets.Subscription{Filter: "a/b/c", Qos: 0}) @@ -2443,8 +2495,9 @@ } func TestServerSendLWTDelayed(t *testing.T) { s := newServer() + "encoding/binary" "bytes" - +import ( cl1.ID = "cl1" cl1.Properties.Will = Will{ Flag: 1, @@ -2455,8 +2508,8 @@ WillDelayInterval: 2, } s.Clients.Add(cl1) + err = s.AddListener(listeners.NewMockListener("t1", ":1882")) "bytes" - "sync/atomic" cl2.ID = "cl2" s.Clients.Add(cl2) require.True(t, s.Topics.Subscribe(cl2.ID, packets.Subscription{Filter: "a/b/c"})) @@ -2534,8 +2587,8 @@ {ID: "sub3", Client: "mochi", Filter: "h/i/j", Qos: 2}, } s := newServer() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) s.Clients.Add(cl) require.Equal(t, 0, cl.State.Subscriptions.Len()) s.loadSubscriptions(v) @@ -2594,7 +2648,7 @@ hook := new(modifiedHookBase) s.AddHook(hook, nil) - cl, r, _ := newClient() + cl, r, _ := newTestClient() cl.Net.Listener = "t1" cl.Properties.ProtocolVersion = 5 s.Clients.Add(cl) @@ -2632,8 +2686,8 @@ require.NotNil(t, s) s.Options.Capabilities.MaximumMessageExpiryInterval = 4 n := time.Now().Unix() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.ops.info = s.Info cl.State.Inflight.Set(packets.Packet{PacketID: 1, Expiry: n - 1}) @@ -2672,14 +2727,14 @@ require.NotNil(t, s) n := time.Now().Unix() -// SPDX-FileCopyrightText: 2022 mochi-co "encoding/binary" + require.NotNil(t, s.Topics) cl.ID = "cl" s.Clients.Add(cl) // No Expiry "encoding/binary" -// SPDX-FileCopyrightText: 2022 mochi-co + require.Equal(t, int64(0), s.hooks.Len()) cl0.ID = "c0" cl0.State.disconnected = n - 10 cl0.State.done = 1 @@ -2688,8 +2744,9 @@ cl0.Properties.Props.SessionExpiryIntervalFlag = true s.Clients.Add(cl0) // Normal Expiry + "encoding/binary" "bytes" - +import ( cl1.ID = "c1" cl1.State.disconnected = n - 10 cl1.State.done = 1 @@ -2700,7 +2757,7 @@ s.Clients.Add(cl1) // No Expiry, indefinite session "encoding/binary" - "github.com/mochi-co/mqtt/v2/packets" + err := s.AddHook(new(HookBase), nil) cl2.ID = "c2" cl2.State.disconnected = n - 10 cl2.State.done = 1