yosssi / gmq

Pure Go MQTT Client
MIT License
345 stars 46 forks source link

SubACK failure not reported to toplevel. #12

Open alessandrocarminati opened 6 years ago

alessandrocarminati commented 6 years ago

Hello, I have a use case where it is required to me to have topics restricted by ACLs. In one of such scenarios; I had serious problem of debug, because when a subscription fails, it does not report this event to the toplevel. To facilitate my usage of this library I modified the client.go file as follow

var (
        ErrAlreadyConnected = errors.New("the Client has already connected to the Server")
        ErrNotYetConnected  = errors.New("the Client has not yet connected to the Server")
        ErrCONNACKTimeout   = errors.New("the CONNACK Packet was not received within a reasonalbe amount of time")
        ErrPINGRESPTimeout  = errors.New("the PINGRESP Packet was not received within a reasonalbe amount of time")
        ErrPacketIDExhaused = errors.New("Packet Identifiers are exhausted")
        ErrInvalidPINGRESP  = errors.New("invalid PINGRESP Packet")
        ErrInvalidSUBACK    = errors.New("invalid SUBACK Packet")  //added to report suback failed event
        ErrDeniedSUBACK     = errors.New("Subdenied")
)

// handleSUBACK handles the SUBACK Packet.
func (cli *Client) handleSUBACK(p packet.Packet) error {
        // Lock for update.
        cli.muConn.Lock()
        cli.muSess.Lock()

        // Unlock.
        defer cli.muConn.Unlock()
        defer cli.muSess.Unlock()

        // Extract the Packet Identifier of the Packet.
        id := p.(*packet.SUBACK).PacketID

        // Validate the Packet Identifier.
        if err := cli.validatePacketID(cli.sess.sendingPackets, id, packet.TypeSUBSCRIBE); err != nil {
                return err
        }

    // Get the subscription requests of the SUBSCRIBE Packet.
        subreqs := cli.sess.sendingPackets[id].(*packet.SUBSCRIBE).SubReqs

        // Delete the SUBSCRIBE Packet from the Session.
        delete(cli.sess.sendingPackets, id)

        // Get the Return Codes of the SUBACK Packet.
        returnCodes := p.(*packet.SUBACK).ReturnCodes

        // Check the lengths of the Return Codes.
        if len(returnCodes) != len(subreqs) {
                return ErrInvalidSUBACK
        }

    // Set the subscriptions to the Network Connection.
        for i, code := range returnCodes {
                // Skip if the Return Code is failure.
                if code == packet.SUBACKRetFailure {
                        return ErrDeniedSUBACK //added to report suback failed event
                        continue
                }

                // Get the Topic Filter.
                topicFilter := string(subreqs[i].TopicFilter)

                // Move the subscription information from
                // unackSubs to ackedSubs.
                cli.conn.ackedSubs[topicFilter] = cli.conn.unackSubs[topicFilter]
                delete(cli.conn.unackSubs, topicFilter)
        }

    return nil
}

is there any reason this condition weren't reported? Regards.