diff --git a/lib/dgram.js b/lib/dgram.js index 483794b72..8130bace8 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -24,6 +24,10 @@ var events = require('events'); var UDP = process.binding('udp_wrap').UDP; +var BIND_STATE_UNBOUND = 0; +var BIND_STATE_BINDING = 1; +var BIND_STATE_BOUND = 2; + // lazily loaded var dns = null; var net = null; @@ -90,7 +94,7 @@ function Socket(type, listener) { this._handle = handle; this._receiving = false; - this._bound = false; + this._bindState = BIND_STATE_UNBOUND; this.type = type; this.fd = null; // compatibility hack @@ -116,6 +120,8 @@ Socket.prototype.bind = function(port, address, callback) { // resolve address first self._handle.lookup(address, function(err, ip) { + self._bindState = BIND_STATE_UNBOUND; + if (!self._handle) return; // handle has been closed in the mean time @@ -132,11 +138,13 @@ Socket.prototype.bind = function(port, address, callback) { self._handle.onmessage = onMessage; self._handle.recvStart(); self._receiving = true; - self._bound = true; + self._bindState = BIND_STATE_BOUND; self.fd = -42; // compatibility hack self.emit('listening'); }); + + self._bindState = BIND_STATE_BINDING; }; @@ -175,8 +183,10 @@ Socket.prototype.send = function(buffer, self._healthCheck(); - if (!self._bound) { + if (self._bindState == BIND_STATE_UNBOUND) self.bind(0, null); + + if (self._bindState != BIND_STATE_BOUND) { self.once('listening', function() { self.send(buffer, offset, length, port, address, callback); }); diff --git a/test/simple/test-dgram-implicit-bind.js b/test/simple/test-dgram-implicit-bind.js new file mode 100644 index 000000000..6039629c4 --- /dev/null +++ b/test/simple/test-dgram-implicit-bind.js @@ -0,0 +1,49 @@ +// 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 dgram = require('dgram'); + +var source = dgram.createSocket('udp4'); +var target = dgram.createSocket('udp4'); +var messages = 0; + +process.on('exit', function() { + assert.equal(messages, 2); +}); + +target.on('message', function(buf) { + if (buf.toString() === 'abc') ++messages; + if (buf.toString() === 'def') ++messages; + if (messages === 2) { + source.close(); + target.close(); + } +}); + +target.on('listening', function() { + // Second .send() call should not throw a bind error. + source.send(Buffer('abc'), 0, 3, common.PORT, '127.0.0.1'); + source.send(Buffer('def'), 0, 3, common.PORT, '127.0.0.1'); +}); + +target.bind(common.PORT);