Skip to content

Commit

Permalink
socket: only send client metadata once per socket (#105)
Browse files Browse the repository at this point in the history
Periodic cluster synchronisation calls isMaster() which currently resends the
"client" metadata every call - the spec specifies:

	isMaster commands issued after the initial connection handshake MUST NOT
	contain handshake arguments

	https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake

This hotfix prevents subsequent isMaster calls from sending the client metadata
again - fixes #101 and fixes #103.

Thanks to @changwoo-nam @qhenkart @canthefason @jyoon17 for spotting the initial
issue, opening tickets, and having the problem debugged with a PoC fix before I
even woke up.
  • Loading branch information
domodwyer authored Feb 13, 2018
1 parent 896bbb8 commit 9be26bd
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
40 changes: 31 additions & 9 deletions cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,38 @@ func (cluster *mongoCluster) isMaster(socket *mongoSocket, result *isMasterResul
session := newSession(Monotonic, cluster, 10*time.Second)
session.setSocket(socket)

// provide some meta infos on the client,
// see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake
// for details
metaInfo := bson.M{"driver": bson.M{"name": "mgo", "version": "globalsign"},
"os": bson.M{"type": runtime.GOOS, "architecture": runtime.GOARCH}}
var cmd = bson.D{{Name: "isMaster", Value: 1}}

// Send client metadata to the server to identify this socket if this is
// the first isMaster call only.
//
// isMaster commands issued after the initial connection handshake MUST NOT contain handshake arguments
// https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake
//
socket.sendMeta.Do(func() {
var meta = bson.M{
"driver": bson.M{
"name": "mgo",
"version": "globalsign",
},
"os": bson.M{
"type": runtime.GOOS,
"architecture": runtime.GOARCH,
},
}

if cluster.appName != "" {
metaInfo["application"] = bson.M{"name": cluster.appName}
}
err := session.Run(bson.D{{Name: "isMaster", Value: 1}, {Name: "client", Value: metaInfo}}, result)
// Include the application name if set
if cluster.appName != "" {
meta["application"] = bson.M{"name": cluster.appName}
}

cmd = append(cmd, bson.DocElem{
Name: "client",
Value: meta,
})
})

err := session.Run(cmd, result)
session.Close()
return err
}
Expand Down
1 change: 1 addition & 0 deletions socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type mongoSocket struct {
dead error
serverInfo *mongoServerInfo
closeAfterIdle bool
sendMeta sync.Once
}

type queryOpFlags uint32
Expand Down

0 comments on commit 9be26bd

Please sign in to comment.