Beispiel #1
0
// client
function responseKeepAlive(res, req) {
  var socket = req.socket;

  if (!req.shouldKeepAlive) {
    if (socket.writable) {
      debug('AGENT socket.destroySoon()');
      socket.destroySoon();
    }
    assert(!socket.writable);
  } else {
    debug('AGENT socket keep-alive');
    if (req.timeoutCb) {
      socket.setTimeout(0, req.timeoutCb);
      req.timeoutCb = null;
    }
    socket.removeListener('close', socketCloseListener);
    socket.removeListener('error', socketErrorListener);
    socket.once('error', freeSocketErrorListener);
    // There are cases where _handle === null. Avoid those. Passing null to
    // nextTick() will call initTriggerId() to retrieve the id.
    const asyncId = socket._handle ? socket._handle.getAsyncId() : null;
    // Mark this socket as available, AFTER user-added end
    // handlers have a chance to run.
    nextTick(asyncId, emitFreeNT, socket);
  }
}
Beispiel #2
0
 this.createSocket(req, options, function(err, newSocket) {
   if (err) {
     nextTick(newSocket._handle.getAsyncId(), function() {
       req.emit('error', err);
     });
     return;
   }
   newSocket.emit('free');
 });
Beispiel #3
0
function write_(msg, chunk, encoding, callback, fromEnd) {
  if (msg.finished) {
    const err = new errors.Error('ERR_STREAM_WRITE_AFTER_END');
    nextTick(msg.socket && msg.socket[async_id_symbol],
             writeAfterEndNT.bind(msg),
             err,
             callback);

    return true;
  }

  if (!msg._header) {
    msg._implicitHeader();
  }

  if (!msg._hasBody) {
    debug('This type of response MUST NOT have a body. ' +
          'Ignoring write() calls.');
    return true;
  }

  if (!fromEnd && typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
    throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'first argument',
                               ['string', 'Buffer']);
  }


  // If we get an empty string or buffer, then just do nothing, and
  // signal the user to keep writing.
  if (chunk.length === 0) return true;

  if (!fromEnd && msg.connection && !msg.connection.corked) {
    msg.connection.cork();
    process.nextTick(connectionCorkNT, msg.connection);
  }

  var len, ret;
  if (msg.chunkedEncoding) {
    if (typeof chunk === 'string')
      len = Buffer.byteLength(chunk, encoding);
    else
      len = chunk.length;

    msg._send(len.toString(16), 'latin1', null);
    msg._send(crlf_buf, null, null);
    msg._send(chunk, encoding, null);
    ret = msg._send(crlf_buf, null, callback);
  } else {
    ret = msg._send(chunk, encoding, callback);
  }

  debug('write ret = ' + ret);
  return ret;
}
Beispiel #4
0
Server.prototype._emitCloseIfDrained = function() {
  debug('SERVER _emitCloseIfDrained');

  if (this._handle || this._connections) {
    debug('SERVER handle? %j   connections? %d',
          !!this._handle, this._connections);
    return;
  }

  const asyncId = this._handle ? this[async_id_symbol] : null;
  nextTick(asyncId, emitCloseNT, this);
};
Beispiel #5
0
 return function handleSocketCreation_Inner(err, socket) {
   if (err) {
     const asyncId = (socket && socket._handle && socket._handle.getAsyncId) ?
       socket._handle.getAsyncId() :
       null;
     nextTick(asyncId, () => request.emit('error', err));
     return;
   }
   if (informRequest)
     request.onSocket(socket);
   else
     socket.emit('free');
 };
Beispiel #6
0
// Provide a better error message when we call end() as a result
// of the other side sending a FIN.  The standard 'write after end'
// is overly vague, and makes it seem like the user's code is to blame.
function writeAfterFIN(chunk, encoding, cb) {
  if (typeof encoding === 'function') {
    cb = encoding;
    encoding = null;
  }

  var er = new Error('This socket has been ended by the other party');
  er.code = 'EPIPE';
  // TODO: defer error events consistently everywhere, not just the cb
  this.emit('error', er);
  if (typeof cb === 'function') {
    nextTick(this[async_id_symbol], cb, er);
  }
}
Beispiel #7
0
Socket.prototype.close = function(callback) {
  if (typeof callback === 'function')
    this.on('close', callback);

  if (this._queue) {
    this._queue.push(this.close.bind(this));
    return this;
  }

  this._healthCheck();
  this._stopReceiving();
  this._handle.close();
  this._handle = null;
  nextTick(this[async_id_symbol], socketCloseNT, this);

  return this;
};
Beispiel #8
0
function _writeRaw(data, encoding, callback) {
  const conn = this.connection;
  if (conn && conn.destroyed) {
    // The socket was destroyed. If we're still trying to write to it,
    // then we haven't gotten the 'close' event yet.
    return false;
  }

  if (typeof encoding === 'function') {
    callback = encoding;
    encoding = null;
  }

  if (conn && conn._httpMessage === this && conn.writable && !conn.destroyed) {
    // There might be pending data in the this.output buffer.
    if (this.output.length) {
      this._flushOutput(conn);
    } else if (!data.length) {
      if (typeof callback === 'function') {
        let socketAsyncId = this.socket[async_id_symbol];
        // If the socket was set directly it won't be correctly initialized
        // with an async_id_symbol.
        // TODO(AndreasMadsen): @trevnorris suggested some more correct
        // solutions in:
        // https://github.com/nodejs/node/pull/14389/files#r128522202
        if (socketAsyncId === undefined) socketAsyncId = null;

        nextTick(socketAsyncId, callback);
      }
      return true;
    }
    // Directly write to socket.
    return conn.write(data, encoding, callback);
  }
  // Buffer, as long as we're not destroyed.
  this.output.push(data);
  this.outputEncodings.push(encoding);
  this.outputCallbacks.push(callback);
  this.outputSize += data.length;
  this._onPendingData(data.length);
  return false;
}
Beispiel #9
0
function doSend(ex, self, ip, list, address, port, callback) {
  if (ex) {
    if (typeof callback === 'function') {
      callback(ex);
      return;
    }

    self.emit('error', ex);
    return;
  } else if (!self._handle) {
    return;
  }

  var req = new SendWrap();
  req.list = list;  // Keep reference alive.
  req.address = address;
  req.port = port;
  if (callback) {
    req.callback = callback;
    req.oncomplete = afterSend;
  }
  // node::SendWrap isn't instantiated and attached to the JS instance of
  // SendWrap above until send() is called. So don't set the init trigger id
  // until now.
  setInitTriggerId(self[async_id_symbol]);
  var err = self._handle.send(req,
                              list,
                              list.length,
                              port,
                              ip,
                              !!callback);
  if (err && callback) {
    // don't emit as error, dgram_legacy.js compatibility
    const ex = exceptionWithHostPort(err, 'send', address, port);
    nextTick(self[async_id_symbol], callback, ex);
  }
}
const { checkInvocations } = require('./hook-checks');
const internal = require('internal/process/next_tick');

const hooks = initHooks();
hooks.enable();

const rootAsyncId = async_hooks.executionAsyncId();

// public
process.nextTick(common.mustCall(function() {
  assert.strictEqual(async_hooks.triggerAsyncId(), rootAsyncId);
}));

// internal default
internal.nextTick(null, common.mustCall(function() {
  assert.strictEqual(async_hooks.triggerAsyncId(), rootAsyncId);
}));

// internal default
internal.nextTick(undefined, common.mustCall(function() {
  assert.strictEqual(async_hooks.triggerAsyncId(), rootAsyncId);
}));

// internal
internal.nextTick(rootAsyncId + 1, common.mustCall(function() {
  assert.strictEqual(async_hooks.triggerAsyncId(), rootAsyncId + 1);
}));

process.on('exit', function() {
  hooks.sanityCheck();
Beispiel #11
0
 function end(err, connections) {
   nextTick(self[async_id_symbol], cb, err, connections);
 }
Beispiel #12
0
function setupListenHandle(address, port, addressType, backlog, fd) {
  debug('setupListenHandle', address, port, addressType, backlog, fd);

  // If there is not yet a handle, we need to create one and bind.
  // In the case of a server sent via IPC, we don't need to do this.
  if (this._handle) {
    debug('setupListenHandle: have a handle already');
  } else {
    debug('setupListenHandle: create a handle');

    var rval = null;

    // Try to bind to the unspecified IPv6 address, see if IPv6 is available
    if (!address && typeof fd !== 'number') {
      rval = createServerHandle('::', port, 6, fd);

      if (typeof rval === 'number') {
        rval = null;
        address = '0.0.0.0';
        addressType = 4;
      } else {
        address = '::';
        addressType = 6;
      }
    }

    if (rval === null)
      rval = createServerHandle(address, port, addressType, fd);

    if (typeof rval === 'number') {
      var error = exceptionWithHostPort(rval, 'listen', address, port);
      process.nextTick(emitErrorNT, this, error);
      return;
    }
    this._handle = rval;
  }

  this[async_id_symbol] = getNewAsyncId(this._handle);
  this._handle.onconnection = onconnection;
  this._handle.owner = this;

  // Use a backlog of 512 entries. We pass 511 to the listen() call because
  // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
  // which will thus give us a backlog of 512 entries.
  var err = this._handle.listen(backlog || 511);

  if (err) {
    var ex = exceptionWithHostPort(err, 'listen', address, port);
    this._handle.close();
    this._handle = null;
    nextTick(this[async_id_symbol], emitErrorNT, this, ex);
    return;
  }

  // generate connection key, this should be unique to the connection
  this._connectionKey = addressType + ':' + address + ':' + port;

  // unref the handle if the server was unref'ed prior to listening
  if (this._unref)
    this.unref();

  nextTick(this[async_id_symbol], emitListeningNT, this);
}
Beispiel #13
0
 function end(err, connections) {
   const asyncId = self._handle ? self[async_id_symbol] : null;
   nextTick(asyncId, cb, err, connections);
 }
Beispiel #14
0
function lookupAndConnect(self, options) {
  var host = options.host || 'localhost';
  var port = options.port;
  var localAddress = options.localAddress;
  var localPort = options.localPort;

  if (localAddress && !cares.isIP(localAddress)) {
    throw new errors.TypeError('ERR_INVALID_IP_ADDRESS', localAddress);
  }

  if (localPort && typeof localPort !== 'number') {
    throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
                               'options.localPort',
                               'number',
                               localPort);
  }

  if (typeof port !== 'undefined') {
    if (typeof port !== 'number' && typeof port !== 'string') {
      throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
                                 'options.port',
                                 ['number', 'string'],
                                 port);
    }
    if (!isLegalPort(port)) {
      throw new errors.RangeError('ERR_SOCKET_BAD_PORT', port);
    }
  }
  port |= 0;

  // If host is an IP, skip performing a lookup
  var addressType = cares.isIP(host);
  if (addressType) {
    nextTick(self[async_id_symbol], function() {
      if (self.connecting)
        internalConnect(self, host, port, addressType, localAddress, localPort);
    });
    return;
  }

  if (options.lookup && typeof options.lookup !== 'function')
    throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
                               'options.lookup',
                               'Function',
                               options.lookup);

  var dnsopts = {
    family: options.family,
    hints: options.hints || 0
  };

  if (dnsopts.family !== 4 && dnsopts.family !== 6 && dnsopts.hints === 0) {
    dnsopts.hints = dns.ADDRCONFIG;
  }

  debug('connect: find host', host);
  debug('connect: dns options', dnsopts);
  self._host = host;
  var lookup = options.lookup || dns.lookup;
  setInitTriggerId(self[async_id_symbol]);
  lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
    self.emit('lookup', err, ip, addressType, host);

    // It's possible we were destroyed while looking this up.
    // XXX it would be great if we could cancel the promise returned by
    // the look up.
    if (!self.connecting) return;

    if (err) {
      // net.createConnection() creates a net.Socket object and
      // immediately calls net.Socket.connect() on it (that's us).
      // There are no event listeners registered yet so defer the
      // error event to the next tick.
      err.host = options.host;
      err.port = options.port;
      err.message = err.message + ' ' + options.host + ':' + options.port;
      process.nextTick(connectErrorNT, self, err);
    } else {
      self._unrefTimer();
      internalConnect(self,
                      ip,
                      port,
                      addressType,
                      localAddress,
                      localPort);
    }
  });
}
'use strict';
// Flags: --no-force-async-hooks-checks --expose-internals
const common = require('../common');

const async_hooks = require('internal/async_hooks');
const internal = require('internal/process/next_tick');

// Using undefined as the triggerAsyncId.
// Ref: https://github.com/nodejs/node/issues/14386
// Ref: https://github.com/nodejs/node/issues/14381
// Ref: https://github.com/nodejs/node/issues/14368
internal.nextTick(undefined, common.mustCall());

// Negative asyncIds and invalid type name
async_hooks.emitInit(-1, null, -1, {});
async_hooks.emitBefore(-1, -1);
async_hooks.emitAfter(-1);
async_hooks.emitDestroy(-1);