Skip to content

Commit

Permalink
socket: only send client metadata once per socket
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 committed Feb 13, 2018
1 parent 896bbb8 commit 86bd675
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 86bd675

Please sign in to comment.