Fix race condition for nextStart and nextEnd.

This commit is contained in:
Martin Dosch 2024-03-16 19:04:09 +01:00
parent 73f06c9f3d
commit 8ab32d885f

26
xmpp.go
View File

@ -38,6 +38,7 @@ import (
"slices"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/crypto/pbkdf2"
@ -60,6 +61,9 @@ var DefaultConfig = &tls.Config{}
// DebugWriter is the writer used to write debugging output to.
var DebugWriter io.Writer = os.Stderr
// Mutex to prevent multiple access to xml.Decoder
var nextMutex sync.Mutex
// Cookie is a unique XMPP session identifier
type Cookie uint64
@ -917,7 +921,6 @@ type IQ struct {
}
// Recv waits to receive the next XMPP stanza.
// Return type is either a presence notification or a chat message.
func (c *Client) Recv() (stanza interface{}, err error) {
for {
_, val, err := next(c.p)
@ -1461,29 +1464,46 @@ type rosterItem struct {
// Scan XML token stream to find next StartElement.
func nextStart(p *xml.Decoder) (xml.StartElement, error) {
for {
nextMutex.Lock()
t, err := p.Token()
if err != nil || t == nil {
nextMutex.Unlock()
return xml.StartElement{}, err
}
switch t := t.(type) {
case xml.StartElement:
nextMutex.Unlock()
return t, nil
// Also check for stream end element and stop waiting
// for new start elements if we received a closing stream
// element.
case xml.EndElement:
if t.Name.Local == "stream" {
nextMutex.Unlock()
return xml.StartElement{}, nil
}
}
nextMutex.Unlock()
}
}
// Scan XML token stream to find next EndElement
func nextEnd(p *xml.Decoder) (xml.EndElement, error) {
p.Strict = false
for {
t, err := p.RawToken()
if err != nil || t == nil {
nextMutex.Lock()
to, err := p.RawToken()
if err != nil || to == nil {
nextMutex.Unlock()
return xml.EndElement{}, err
}
t := xml.CopyToken(to)
switch t := t.(type) {
case xml.EndElement:
nextMutex.Unlock()
return t, nil
}
nextMutex.Unlock()
}
}