From 9be26bd91ab2fff0bd27ef5c2b148fbb3a6c46a9 Mon Sep 17 00:00:00 2001 From: Dom Date: Tue, 13 Feb 2018 11:21:57 +0000 Subject: [PATCH] socket: only send client metadata once per socket (#105) 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. --- cluster.go | 40 +++++++++++++++++++++++++++++++--------- socket.go | 1 + 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/cluster.go b/cluster.go index 7fc639c24..087da61e5 100644 --- a/cluster.go +++ b/cluster.go @@ -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 } diff --git a/socket.go b/socket.go index f6158189c..a9124b043 100644 --- a/socket.go +++ b/socket.go @@ -54,6 +54,7 @@ type mongoSocket struct { dead error serverInfo *mongoServerInfo closeAfterIdle bool + sendMeta sync.Once } type queryOpFlags uint32