Example #1
0
func (c *conn) getCookie() data.Cookie {
	var buf [8]byte
	if _, err := c.Rand().Read(buf[:]); err != nil {
		panic("Failed to read random bytes: " + err.Error())
	}
	return data.Cookie(binary.LittleEndian.Uint64(buf[:]))
}
Example #2
0
func (s *ConnectionXmppSuite) Test_Next_returnsNothingIfTheInflightIsToAnotherReceiver(c *C) {
	mockIn := &mockConnIOReaderWriter{read: []byte("<client:iq xmlns:client='jabber:client' type='result' id='100000' from='*****@*****.**'></client:iq>")}
	conn := conn{
		in:        xml.NewDecoder(mockIn),
		inflights: make(map[data.Cookie]inflight),
	}
	cookie := data.Cookie(1048576)
	conn.inflights[cookie] = inflight{to: "*****@*****.**"}
	_, err := conn.Next()
	c.Assert(err, Equals, io.EOF)
}
Example #3
0
// Next reads stanzas from the server. If the stanza is a reply, it dispatches
// it to the correct channel and reads the next message. Otherwise it returns
// the stanza for processing.
func (c *conn) Next() (stanza data.Stanza, err error) {
	for {
		if stanza.Name, stanza.Value, err = next(c); err != nil {
			return
		}

		if _, ok := stanza.Value.(*data.StreamClose); ok {
			log.Println("xmpp: received closing stream tag")
			go c.closeImmediately()
			return
		}

		if iq, ok := stanza.Value.(*data.ClientIQ); ok && (iq.Type == "result" || iq.Type == "error") {
			var cookieValue uint64
			if cookieValue, err = strconv.ParseUint(iq.ID, 16, 64); err != nil {
				err = errors.New("xmpp: failed to parse id from iq: " + err.Error())
				return
			}
			cookie := data.Cookie(cookieValue)

			c.lock.Lock()
			inflight, ok := c.inflights[cookie]
			c.lock.Unlock()

			if !ok {
				continue
			}
			if len(inflight.to) > 0 {
				// The reply must come from the address to
				// which we sent the request.
				if inflight.to != iq.From {
					continue
				}
			} else {
				// If there was no destination on the request
				// then the matching is more complex because
				// servers differ in how they construct the
				// reply.
				if len(iq.From) > 0 && iq.From != c.jid && iq.From != utils.RemoveResourceFromJid(c.jid) && iq.From != utils.DomainFromJid(c.jid) {
					continue
				}
			}

			c.lock.Lock()
			delete(c.inflights, cookie)
			c.lock.Unlock()

			inflight.replyChan <- stanza
			continue
		}

		return
	}
}
Example #4
0
func (s *ConnectionXmppSuite) Test_Next_continuesIfIqFromIsNotSimilarToJid(c *C) {
	mockIn := &mockConnIOReaderWriter{read: []byte("<client:iq xmlns:client='jabber:client' type='result' id='100000' from='*****@*****.**'></client:iq>")}
	inflights := make(map[data.Cookie]inflight)
	conn := conn{
		in:        xml.NewDecoder(mockIn),
		inflights: inflights,
		jid:       "[email protected]/blah",
	}
	cookie := data.Cookie(1048576)
	conn.inflights[cookie] = inflight{}
	_, err := conn.Next()
	c.Assert(err, Equals, io.EOF)
	_, ok := conn.inflights[cookie]
	c.Assert(ok, Equals, true)
}
Example #5
0
func (s *SessionSuite) Test_watchTimeouts_cancelsTimedoutRequestsAndForgetsAboutThem(c *C) {
	now := time.Now()
	timeouts := map[data.Cookie]time.Time{
		data.Cookie(1): now.Add(-1 * time.Second),
		data.Cookie(2): now.Add(10 * time.Second),
	}

	sess := &session{
		connStatus: CONNECTED,
		timeouts:   timeouts,
		conn:       xmpp.NewConn(nil, nil, ""),
	}

	go func() {
		<-time.After(1 * time.Second)
		sess.connStatus = DISCONNECTED
	}()

	sess.watchTimeout()
	c.Check(sess.timeouts, HasLen, 1)

	_, ok := sess.timeouts[data.Cookie(2)]
	c.Check(ok, Equals, true)
}
Example #6
0
func (s *ConnectionXmppSuite) Test_Next_removesIfThereIsNoFrom(c *C) {
	mockIn := &mockConnIOReaderWriter{read: []byte("<client:iq xmlns:client='jabber:client' type='result' id='100000'></client:iq>")}
	inflights := make(map[data.Cookie]inflight)
	conn := conn{
		in:        xml.NewDecoder(mockIn),
		inflights: inflights,
	}
	cookie := data.Cookie(1048576)
	reply := make(chan data.Stanza, 1)
	conn.inflights[cookie] =
		inflight{
			replyChan: reply,
		}

	go func() {
		<-reply
	}()

	_, err := conn.Next()
	c.Assert(err, Equals, io.EOF)
	_, ok := conn.inflights[cookie]
	c.Assert(ok, Equals, false)
}