Beispiel #1
0
func wshandler(ws *websocket.Conn) {
	flag.Parse()
	var mqcon net.Conn
	var err error
	if *bs {
		conf := tls.Config{InsecureSkipVerify: *bsinsec}
		if *bcert != "" && *bkey != "" {
			Cert, err := tls.LoadX509KeyPair(*bcert, *bkey)
			if err != nil {
				fmt.Println("LoadX509KeyPair:", err)
				return
			}
			conf.Certificates = []tls.Certificate{Cert}
		}
		mqcon, err = tls.Dial("tcp", *bhost+":"+*bport, &conf)
	} else {
		mqcon, err = net.Dial("tcp", *bhost+":"+*bport)
	}

	if err != nil {
		fmt.Println("mqcon error:", err.Error())
		ws.Close()
		return
	}
	ws.PayloadType = websocket.BinaryFrame

	bmqcon := bufio.NewReadWriter(bufio.NewReader(mqcon), bufio.NewWriter(mqcon))
	bws := bufio.NewReadWriter(bufio.NewReader(ws), bufio.NewWriter(ws))

	go func() {
		for {
			msg, err := mqtt.DecodeOneMessage(bmqcon, nil)
			//			fmt.Println("brok->", msg)
			if err != nil {
				mqcon.Close()
				return
			}
			wbuffer := new(bytes.Buffer)
			msg.Encode(wbuffer)
			bws.Write(wbuffer.Bytes())
			bws.Flush()
			wbuffer.Truncate(wbuffer.Len())
		}
	}()
	for {
		msg, err := mqtt.DecodeOneMessage(bws, nil)
		//		fmt.Println("webs->", msg)
		if err != nil {
			ws.Close()
			return
		}
		msg.Encode(bmqcon)
		bmqcon.Flush()
	}
}
Beispiel #2
0
func (c *Connection) handleConnection() {
	defer func() {
		c.Conn.Close()
		close(c.jobs)
	}()

	for {
		clientLog := log.WithField("clientid", c.sess.Clientid)
		m, err := proto.DecodeOneMessage(c.Conn, nil)
		if err != nil {

			clientLog.Warnf("disconnected unexpectedly: %s", err)

			if c.sess.WillMsg != nil {
				clientLog.Info("Sending Will message")
				c.handlePublish(c.sess.WillMsg)
			}

			c.sess.Status = ClientUnAvailable
			return
		}
		clientLog.Infof("incoming msg type: %T", m)
		switch m := m.(type) {
		case *proto.Connect:
			c.handleConnect(m)
		case *proto.Publish:
			c.handlePublish(m)
		case *proto.PubAck:
			c.handlePubAck(m)
		case *proto.PubRel:
			c.handlePubRel(m)
		case *proto.PubRec:
			c.handlePubRec(m)
		case *proto.PubComp:
			c.handlePubComp(m)
		case *proto.PingReq:
			c.submit(&proto.PingResp{})
		case *proto.Disconnect:
			c.handleDisconnect(m)
			c.sess.Status = ClientDisconnectedNormally
			return
		case *proto.Subscribe:
			c.handleSubscribe(m)
		case *proto.Unsubscribe:
			c.handleUnsubscribe(m)
		default:
			clientLog.Warnf("unknown msg type %T, continue.", m)
		}
		continue // loop until Disconnect comes.
	}
}
Beispiel #3
0
func (c *ClientConn) reader() {
	defer func() {
		// Cause the writer to exit.
		close(c.out)
		// Cause any goroutines waiting on messages to arrive to exit.
		close(c.Incoming)
		c.conn.Close()
	}()

	for {
		// TODO: timeout (first message and/or keepalives)
		m, err := proto.DecodeOneMessage(c.conn, nil)
		if err != nil {
			if err == io.EOF {
				return
			}
			if strings.HasSuffix(err.Error(), "use of closed network connection") {
				return
			}
			log.Print("cli reader: ", err)
			return
		}

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

		switch m := m.(type) {
		case *proto.Publish:
			c.Incoming <- m
		case *proto.PubAck:
			// ignore these
			continue
		case *proto.ConnAck:
			c.connack <- m
		case *proto.SubAck:
			c.suback <- m
		case *proto.Disconnect:
			return
		case *proto.PingResp:
			continue
			// do nothing
		default:
			log.Printf("cli reader: got msg type %T", m)
		}
	}
}
Beispiel #4
0
func (c *incomingConn) reader() {
	// On exit, close the connection and arrange for the writer to exit
	// by closing the output channel.
	defer func() {
		c.conn.Close()
		c.svr.stats.clientDisconnect()
		close(c.jobs)
	}()

	for {
		// TODO: timeout (first message and/or keepalives)
		m, err := proto.DecodeOneMessage(c.conn, nil)
		if err != nil {
			if err == io.EOF {
				return
			}
			if strings.HasSuffix(err.Error(), "use of closed network connection") {
				return
			}
			log.Print("reader: ", err)
			return
		}
		c.svr.stats.messageRecv()

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

		switch m := m.(type) {
		case *proto.Connect:
			rc := proto.RetCodeAccepted

			if m.ProtocolName != "MQIsdp" ||
				m.ProtocolVersion != 3 {
				log.Print("reader: reject connection from ", m.ProtocolName, " version ", m.ProtocolVersion)
				rc = proto.RetCodeUnacceptableProtocolVersion
			}

			// Check client id.
			if len(m.ClientId) < 1 || len(m.ClientId) > 23 {
				rc = proto.RetCodeIdentifierRejected
			}
			c.clientid = m.ClientId

			// Disconnect existing connections.
			if existing := c.add(); existing != nil {
				disconnect := &proto.Disconnect{}
				r := existing.submitSync(disconnect)
				r.wait()
				existing.del()
			}
			c.add()

			// TODO: Last will

			connack := &proto.ConnAck{
				ReturnCode: rc,
			}
			c.submit(connack)

			// close connection if it was a bad connect
			if rc != proto.RetCodeAccepted {
				log.Printf("Connection refused for %v: %v", c.conn.RemoteAddr(), ConnectionErrors[rc])
				return
			}

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

		case *proto.Publish:
			// TODO: Proper QoS support
			if m.Header.QosLevel != proto.QosAtMostOnce {
				log.Printf("reader: no support for QoS %v yet", m.Header.QosLevel)
				return
			}
			if isWildcard(m.TopicName) {
				log.Print("reader: ignoring PUBLISH with wildcard topic ", m.TopicName)
			} else {
				c.svr.subs.submit(c, m)
			}
			c.submit(&proto.PubAck{MessageId: m.MessageId})

		case *proto.PingReq:
			c.submit(&proto.PingResp{})

		case *proto.Subscribe:
			if m.Header.QosLevel != proto.QosAtLeastOnce {
				// protocol error, disconnect
				return
			}
			suback := &proto.SubAck{
				MessageId: m.MessageId,
				TopicsQos: make([]proto.QosLevel, len(m.Topics)),
			}
			for i, tq := range m.Topics {
				// TODO: Handle varying QoS correctly
				c.svr.subs.add(tq.Topic, c)
				suback.TopicsQos[i] = proto.QosAtMostOnce
			}
			c.submit(suback)

			// Process retained messages.
			for _, tq := range m.Topics {
				c.svr.subs.sendRetain(tq.Topic, c)
			}

		case *proto.Unsubscribe:
			for _, t := range m.Topics {
				c.svr.subs.unsub(t, c)
			}
			ack := &proto.UnsubAck{MessageId: m.MessageId}
			c.submit(ack)

		case *proto.Disconnect:
			return

		default:
			log.Printf("reader: unknown msg type %T", m)
			return
		}
	}
}