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() } }
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. } }
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) } } }
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 } } }