Esempio n. 1
0
File: stats.go Progetto: zwczou/mqtt
func statsMessage(topic string, stat int64) *packets.PublishPacket {
	p := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
	p.Qos = 1
	p.Retain = true
	p.Dup = false
	p.TopicName = topic
	p.Payload = []byte(fmt.Sprintf("%v", stat))
	return p
}
Esempio n. 2
0
File: conn.go Progetto: zwczou/mqtt
func (c *incomingConn) reader() {
	var err error
	var zeroTime time.Time
	var m packets.ControlPacket

	for {
		if c.KeepaliveTimer > 0 {
			c.conn.SetReadDeadline(time.Now().Add(time.Duration(c.KeepaliveTimer) * time.Second))
		} else {
			c.conn.SetReadDeadline(zeroTime)
		}

		m, err = packets.ReadPacket(c.conn)
		if err != nil {
			break
		}
		c.svr.stats.messageRecv()

		if c.svr.Dump {
			log.Printf("INFO: dump  in: %T", m)
		}

		switch m := m.(type) {
		case *packets.ConnectPacket:
			rc := m.Validate()
			if rc != packets.Accepted {
				err = packets.ConnErrors[rc]
				log.Printf("ERROR: Connection refused for %v: %v", c.conn.RemoteAddr(), err)
				goto exit
			}

			// TODO: authorize

			// connack
			connack := packets.NewControlPacket(packets.Connack)
			connack.(*packets.ConnackPacket).ReturnCode = rc
			c.submit(connack)

			c.clientid = m.ClientIdentifier
			c.KeepaliveTimer = m.KeepaliveTimer
			c.connect = m

			// Disconnect existing connections.
			if existing := c.add(); existing != nil {
				disconnect := packets.NewControlPacket(packets.Disconnect)
				r := existing.submitSync(disconnect)
				r.waitTimeout(time.Second)
			}
			c.add()

			// Log in mosquitto format.
			clean := 0
			if m.CleanSession {
				clean = 1
			}
			log.Printf("INFO: New client connected from %v as %v (c%v, k%v).", c.conn.RemoteAddr(), c.clientid, clean, m.KeepaliveTimer)

		case *packets.PublishPacket:
			switch m.Qos {
			case 2:
				pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket)
				pr.PacketID = m.PacketID
				c.submit(pr)
				c.svr.subs.submit(c, m)
			case 1:
				c.svr.subs.submit(c, m)

				pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket)
				pa.PacketID = m.PacketID
				c.submit(pa)
			case 0:
				c.svr.subs.submit(c, m)
			}
		case *packets.PubackPacket:
		case *packets.PubrecPacket:
			prel := packets.NewControlPacket(packets.Pubrel).(*packets.PubrelPacket)
			prel.PacketID = m.PacketID
			c.submit(prel)
		case *packets.PubrelPacket:
			pc := packets.NewControlPacket(packets.Pubcomp).(*packets.PubcompPacket)
			pc.PacketID = m.PacketID
			c.submit(pc)
		case *packets.PubcompPacket:
		case *packets.PingreqPacket:
			pr := packets.NewControlPacket(packets.Pingresp)
			c.submit(pr)
		case *packets.SubscribePacket:
			for i := 0; i < len(m.Topics); i++ {
				topic := m.Topics[i]
				c.svr.subs.add(topic, c)
			}

			suback := packets.NewControlPacket(packets.Suback).(*packets.SubackPacket)
			suback.PacketID = m.PacketID
			suback.GrantedQoss = m.Qoss
			c.submit(suback)

			for _, topic := range m.Topics {
				c.svr.subs.sendRetain(topic, c)
			}
		case *packets.UnsubscribePacket:
			unsuback := packets.NewControlPacket(packets.Unsuback).(*packets.UnsubackPacket)
			unsuback.PacketID = m.PacketID
			for _, t := range m.Topics {
				c.svr.subs.unsub(t, c)
			}
			c.submit(unsuback)

		case *packets.DisconnectPacket:
			goto exit
		default:
			err = fmt.Errorf("unknown msg type %T", m)
			goto exit
		}
	}

exit:
	if err != nil {
		if err != io.EOF && !strings.Contains(err.Error(), "use of closed") {
			log.Printf("ERROR: failed to reader - %s", err)
		}

		if c.connect.WillFlag {
			pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
			pub.Qos = c.connect.WillQos
			pub.Retain = c.connect.WillRetain
			pub.TopicName = c.connect.WillTopic
			pub.Payload = c.connect.WillMessage
			c.svr.subs.submit(c, pub)
		}
	}

	c.del()
	c.svr.subs.unsubAll(c)
	c.svr.stats.clientDisconnect()
	c.conn.Close()
	close(c.stop)
}