From f337595441641ad36f6ab8ae770e56c1673ef692 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 25 Feb 2015 17:19:11 +0100 Subject: [PATCH] lib,src: add unix socket getsockname/getpeername The implementation is a minor API change in that socket.address() now returns a `{ address: '/path/to/socket' }` object, like it does for TCP and UDP sockets. Before this commit, it returned `socket._pipeName`, which is a string when present. Change common.PIPE on Windows from '\\\\.\\pipe\\libuv-test' to '\\\\?\\pipe\\libuv-test'. Windows converts the '.' to a '?' when creating a named pipe, meaning that common.PIPE didn't match the result from NtQueryInformationFile(). Fixes: https://github.com/nodejs/node/issues/954 PR-URL: https://github.com/nodejs/node/pull/956 Reviewed-By: Sam Roberts Reviewed-By: Trevor Norris --- doc/api/net.markdown | 20 ++++++++++++++----- lib/net.js | 8 ++------ src/pipe_wrap.cc | 26 +++++++++++++++++++++++++ src/pipe_wrap.h | 3 +++ test/common.js | 2 +- test/parallel/test-cluster-http-pipe.js | 7 +++++-- test/parallel/test-http-unix-socket.js | 2 ++ test/sequential/test-pipe-address.js | 3 ++- 8 files changed, 56 insertions(+), 15 deletions(-) diff --git a/doc/api/net.markdown b/doc/api/net.markdown index f2be29a6b0d2a4..ee7e487ca91770 100644 --- a/doc/api/net.markdown +++ b/doc/api/net.markdown @@ -255,6 +255,9 @@ Example: Don't call `server.address()` until the `'listening'` event has been emitted. +This method used to return the file path as a string for UNIX sockets and +Windows pipes. As of io.js v1.5.0, it returns the expected object. + ### server.unref() Calling `unref` on a server will allow the program to exit if this is the only @@ -508,14 +511,18 @@ Returns `socket`. The string representation of the remote IP address. For example, `'74.125.127.100'` or `'2001:4860:a005::68'`. +For UNIX sockets and Windows pipes, the file path the socket is connected +to. The remote address for server sockets is always `''`, the empty string. + ### socket.remoteFamily -The string representation of the remote IP family. `'IPv4'` or `'IPv6'`. +The string representation of the remote IP family. `'IPv4'` or `'IPv6'` +for TCP sockets, `'pipe'` for UNIX sockets and Windows pipes. ### socket.remotePort -The numeric representation of the remote port. For example, -`80` or `21`. +The numeric representation of the remote port. For example, `80` or `21`. +`undefined` for UNIX sockets and Windows pipes. ### socket.localAddress @@ -523,10 +530,13 @@ The string representation of the local IP address the remote client is connecting on. For example, if you are listening on `'0.0.0.0'` and the client connects on `'192.168.1.1'`, the value would be `'192.168.1.1'`. +For UNIX sockets and Windows pipes, the file path the socket is listening +on. The local address for client sockets is always `''`, the empty string. + ### socket.localPort -The numeric representation of the local port. For example, -`80` or `21`. +The numeric representation of the local port. For example, `80` or `21`. +`undefined` for UNIX sockets and Windows pipes. ### socket.bytesRead diff --git a/lib/net.js b/lib/net.js index 10e789678440fd..c3ccebb6423f66 100644 --- a/lib/net.js +++ b/lib/net.js @@ -1339,16 +1339,14 @@ Server.prototype.listen = function() { else listen(self, null, h.port | 0, 4, backlog, undefined, h.exclusive); } else if (h.path && isPipeName(h.path)) { - var pipeName = self._pipeName = h.path; - listen(self, pipeName, -1, -1, backlog, undefined, h.exclusive); + listen(self, h.path, -1, -1, backlog, undefined, h.exclusive); } else { throw new Error('Invalid listen argument: ' + h); } } } else if (isPipeName(arguments[0])) { // UNIX socket or Windows pipe. - var pipeName = self._pipeName = arguments[0]; - listen(self, pipeName, -1, -1, backlog); + listen(self, arguments[0], -1, -1, backlog); } else if (arguments[1] === undefined || typeof arguments[1] === 'function' || @@ -1381,8 +1379,6 @@ Server.prototype.address = function() { this._handle.getsockname(out); // TODO(bnoordhuis) Check err and throw? return out; - } else if (this._pipeName) { - return this._pipeName; } else { return null; } diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 2e1ab5b2621c32..c22cac219d5684 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -89,6 +89,10 @@ void PipeWrap::Initialize(Handle target, env->SetProtoMethod(t, "listen", Listen); env->SetProtoMethod(t, "connect", Connect); env->SetProtoMethod(t, "open", Open); + env->SetProtoMethod(t, "getpeername", + GetSockOrPeerName); + env->SetProtoMethod(t, "getsockname", + GetSockOrPeerName); #ifdef _WIN32 env->SetProtoMethod(t, "setPendingInstances", SetPendingInstances); @@ -276,6 +280,28 @@ void PipeWrap::Connect(const FunctionCallbackInfo& args) { } +template +void PipeWrap::GetSockOrPeerName( + const v8::FunctionCallbackInfo& args) { + CHECK(args[0]->IsObject()); + char buffer[1024]; + size_t size = sizeof(buffer); + const PipeWrap* wrap = Unwrap(args.Holder()); + const int err = F(&wrap->handle_, buffer, &size); + if (err == 0) { + const uint8_t* data = reinterpret_cast(buffer); + const String::NewStringType type = String::kNormalString; + Local path = + String::NewFromOneByte(args.GetIsolate(), data, type, size); + Environment* env = Environment::GetCurrent(args); + Local out = args[0].As(); + out->Set(env->address_string(), path); + out->Set(env->family_string(), env->pipe_string()); + } + args.GetReturnValue().Set(err); +} + + } // namespace node NODE_MODULE_CONTEXT_AWARE_BUILTIN(pipe_wrap, node::PipeWrap::Initialize) diff --git a/src/pipe_wrap.h b/src/pipe_wrap.h index 6c74de984b34e6..6c77e355e7fb3b 100644 --- a/src/pipe_wrap.h +++ b/src/pipe_wrap.h @@ -30,6 +30,9 @@ class PipeWrap : public StreamWrap { static void Connect(const v8::FunctionCallbackInfo& args); static void Open(const v8::FunctionCallbackInfo& args); + template + static void GetSockOrPeerName(const v8::FunctionCallbackInfo&); + #ifdef _WIN32 static void SetPendingInstances( const v8::FunctionCallbackInfo& args); diff --git a/test/common.js b/test/common.js index 6ba8201c902227..669c586992ce5f 100644 --- a/test/common.js +++ b/test/common.js @@ -134,7 +134,7 @@ Object.defineProperty(exports, 'hasCrypto', {get: function() { }}); if (exports.isWindows) { - exports.PIPE = '\\\\.\\pipe\\libuv-test'; + exports.PIPE = '\\\\?\\pipe\\libuv-test'; } else { exports.PIPE = exports.tmpDir + '/test.sock'; } diff --git a/test/parallel/test-cluster-http-pipe.js b/test/parallel/test-cluster-http-pipe.js index 4c6dee347bb8e9..f4ee5c240e6854 100644 --- a/test/parallel/test-cluster-http-pipe.js +++ b/test/parallel/test-cluster-http-pipe.js @@ -29,8 +29,11 @@ if (cluster.isMaster) { } http.createServer(function(req, res) { - assert.equal(req.connection.remoteAddress, undefined); - assert.equal(req.connection.localAddress, undefined); // TODO common.PIPE? + assert.equal(req.connection.remoteAddress, ''); + assert.equal(req.connection.remoteFamily, 'pipe'); + assert.equal(req.connection.remotePort, undefined); + assert.equal(req.connection.localAddress, common.PIPE); + assert.equal(req.connection.localPort, undefined); res.writeHead(200); res.end('OK'); }).listen(common.PIPE, function() { diff --git a/test/parallel/test-http-unix-socket.js b/test/parallel/test-http-unix-socket.js index 9ec8c8a1572844..c186906816ace7 100644 --- a/test/parallel/test-http-unix-socket.js +++ b/test/parallel/test-http-unix-socket.js @@ -9,6 +9,7 @@ var headers_ok = false; var body_ok = false; var server = http.createServer(function(req, res) { + assert.equal(req.socket.address().address, common.PIPE); res.writeHead(200, { 'Content-Type': 'text/plain', 'Connection': 'close' @@ -19,6 +20,7 @@ var server = http.createServer(function(req, res) { }); server.listen(common.PIPE, function() { + assert.equal(server.address().address, common.PIPE); var options = { socketPath: common.PIPE, diff --git a/test/sequential/test-pipe-address.js b/test/sequential/test-pipe-address.js index b9e544e97458b4..986c6a6a8b5acb 100644 --- a/test/sequential/test-pipe-address.js +++ b/test/sequential/test-pipe-address.js @@ -15,5 +15,6 @@ server.listen(common.PIPE, function() { }); process.on('exit', function() { - assert.equal(address, common.PIPE); + assert.equal(address.address, common.PIPE); + assert.equal(address.family, 'pipe'); });