This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

net: add localPort to connect options

Expose localPort for binding to a specific port for outbound
connections.

If localAddress is not specified '0.0.0.0' is used for ip4 and '::'
for ip6 connections.

Fixes #7092
  • Loading branch information...
1 parent a226be4 commit 59baab277691dcc7d788724020084414b96de22c @tjfontaine tjfontaine committed with indutny Feb 18, 2014
Showing with 147 additions and 7 deletions.
  1. +2 −0 doc/api/net.markdown
  2. +43 −7 lib/net.js
  3. +61 −0 test/simple/test-net-localerror.js
  4. +41 −0 test/simple/test-net-localport.js
View
@@ -64,6 +64,8 @@ For TCP sockets, `options` argument should be an object which specifies:
- `localAddress`: Local interface to bind to for network connections.
+ - `localPort`: Local port to bind to for network connections.
+
- `family` : Version of IP stack. Defaults to `4`.
For local domain sockets, `options` argument should be an object which
View
@@ -776,20 +776,51 @@ function afterWrite(status, handle, req, err) {
}
-function connect(self, address, port, addressType, localAddress) {
+function connect(self, address, port, addressType, localAddress, localPort) {
// TODO return promise from Socket.prototype.connect which
// wraps _connectReq.
assert.ok(self._connecting);
var err;
- if (localAddress) {
- if (addressType === 6) {
- err = self._handle.bind6(localAddress);
- } else {
- err = self._handle.bind(localAddress);
+ if (localAddress || localPort) {
+ if (localAddress && !exports.isIP(localAddress))
+ err = new TypeError(
+ 'localAddress should be a valid IP: ' + localAddress);
+
+ if (localPort && !util.isNumber(localPort))
+ err = new TypeError('localPort should be a number: ' + localPort);
+
+ var bind;
+
+ switch (addressType) {
+ case 4:
+ if (!localAddress)
+ localAddress = '0.0.0.0';
+ bind = self._handle.bind;
+ break;
+ case 6:
+ if (!localAddress)
+ localAddress = '::';
+ bind = self._handle.bind6;
+ break;
+ default:
+ err = new TypeError('Invalid addressType: ' + addressType);
+ break;
+ }
+
+ if (err) {
+ self._destroy(err);
+ return;
}
+ debug('binding to localAddress: %s and localPort: %d',
+ localAddress,
+ localPort);
+
+ bind = bind.bind(self._handle);
+ err = bind(localAddress, localPort);
+
if (err) {
self._destroy(errnoException(err, 'bind'));
return;
@@ -897,7 +928,12 @@ Socket.prototype.connect = function(options, cb) {
// expects remoteAddress to have a meaningful value
ip = ip || (addressType === 4 ? '127.0.0.1' : '0:0:0:0:0:0:0:1');
- connect(self, ip, options.port, addressType, options.localAddress);
+ connect(self,
+ ip,
+ options.port,
+ addressType,
+ options.localAddress,
+ options.localPort);
}
});
}
@@ -0,0 +1,61 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var net = require('net');
+
+var server = net.createServer(function(socket) {
+ assert.ok(false, 'no clients should connect');
+}).listen(common.PORT).on('listening', function() {
+ server.unref();
+
+ function test1(next) {
+ connect({
+ host: '127.0.0.1',
+ port: common.PORT,
+ localPort: 'foobar',
+ },
+ 'localPort should be a number: foobar',
+ next);
+ }
+
+ function test2(next) {
+ connect({
+ host: '127.0.0.1',
+ port: common.PORT,
+ localAddress: 'foobar',
+ },
+ 'localAddress should be a valid IP: foobar',
+ next)
+ }
+
+ test1(test2);
+})
+
+function connect(opts, msg, cb) {
+ var client = net.connect(opts).on('connect', function() {
+ assert.ok(false, 'we should never connect');
+ }).on('error', function(err) {
+ assert.strictEqual(err.message, msg);
+ if (cb) cb();
+ });
+}
@@ -0,0 +1,41 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var net = require('net');
+
+var server = net.createServer(function(socket) {
+ console.log(socket.remotePort);
+ assert.strictEqual(socket.remotePort, common.PORT + 1);
+ socket.end();
+ socket.on('close', function() {
+ server.close();
+ });
+}).listen(common.PORT).on('listening', function() {
+ var client = net.connect({
+ host: '127.0.0.1',
+ port: common.PORT,
+ localPort: common.PORT + 1,
+ }).on('connect', function() {
+ assert.strictEqual(client.localPort, common.PORT + 1);
+ });
+})

0 comments on commit 59baab2

Please sign in to comment.