func writeMessage(conn io.Closer, msg message.Message) error { buf := make([]byte, msg.Len()) _, err := msg.Encode(buf) if err != nil { //glog.Debugf("Write error: %v", err) return err } //glog.Debugf("Writing: %s", msg) return writeMessageBuffer(conn, buf) }
func (this *Ackqueue) insert(pktid uint16, msg message.Message, onComplete interface{}) error { if this.full() { this.grow() } if _, ok := this.emap[pktid]; !ok { // message length ml := msg.Len() // ackmsg am := ackmsg{ Mtype: msg.Type(), State: message.RESERVED, Pktid: msg.PacketId(), Msgbuf: make([]byte, ml), OnComplete: onComplete, } if _, err := msg.Encode(am.Msgbuf); err != nil { return err } this.ring[this.tail] = am this.emap[pktid] = this.tail this.tail = this.increment(this.tail) this.count++ } else { // If packet w/ pktid already exist, then this must be a PUBLISH message // Other message types should never send with the same packet ID pm, ok := msg.(*message.PublishMessage) if !ok { return fmt.Errorf("ack/insert: duplicate packet ID for %s message", msg.Name()) } // If this is a publish message, then the DUP flag must be set. This is the // only scenario in which we will receive duplicate messages. if pm.Dup() { return fmt.Errorf("ack/insert: duplicate packet ID for PUBLISH message, but DUP flag is not set") } // Since it's a dup, there's really nothing we need to do. Moving on... } return nil }
// Ack() takes the ack message supplied and updates the status of messages waiting. func (this *Ackqueue) Ack(msg message.Message) error { this.mu.Lock() defer this.mu.Unlock() switch msg.Type() { case message.PUBACK, message.PUBREC, message.PUBREL, message.PUBCOMP, message.SUBACK, message.UNSUBACK: // Check to see if the message w/ the same packet ID is in the queue i, ok := this.emap[msg.PacketId()] if ok { // If message w/ the packet ID exists, update the message state and copy // the ack message this.ring[i].State = msg.Type() ml := msg.Len() this.ring[i].Ackbuf = make([]byte, ml) _, err := msg.Encode(this.ring[i].Ackbuf) if err != nil { return err } //glog.Debugf("Acked: %v", msg) //} else { //glog.Debugf("Cannot ack %s message with packet ID %d", msg.Type(), msg.PacketId()) } case message.PINGRESP: if this.ping.Mtype == message.PINGREQ { this.ping.State = message.PINGRESP } default: return errAckMessage } return nil }
// writeMessage() writes a message to the outgoing buffer func (this *service) writeMessage(msg message.Message) (int, error) { var ( l int = msg.Len() m, n int err error buf []byte wrap bool ) if this.out == nil { return 0, ErrBufferNotReady } // This is to serialize writes to the underlying buffer. Multiple goroutines could // potentially get here because of calling Publish() or Subscribe() or other // functions that will send messages. For example, if a message is received in // another connetion, and the message needs to be published to this client, then // the Publish() function is called, and at the same time, another client could // do exactly the same thing. // // Not an ideal fix though. If possible we should remove mutex and be lockfree. // Mainly because when there's a large number of goroutines that want to publish // to this client, then they will all block. However, this will do for now. // // FIXME: Try to find a better way than a mutex...if possible. this.wmu.Lock() defer this.wmu.Unlock() buf, wrap, err = this.out.WriteWait(l) if err != nil { return 0, err } if wrap { if len(this.outtmp) < l { this.outtmp = make([]byte, l) } n, err = msg.Encode(this.outtmp[0:]) if err != nil { return 0, err } m, err = this.out.Write(this.outtmp[0:n]) if err != nil { return m, err } } else { n, err = msg.Encode(buf[0:]) if err != nil { return 0, err } m, err = this.out.WriteCommit(n) if err != nil { return 0, err } } this.outStat.increment(int64(m)) return m, nil }