lib,src: port isIPv4() to js
Removes a few lines of C++ code while making `isIPv4()` about 3x faster. `isIPv6()` and `isIP()` for the IPv6 case stay about the same. I removed the homegrown `isIPv4()` in lib/dns.js that utilized a lookup table. It is in fact a little faster than the new `isIPv4()` function but: 1. The difference is only measurable at around 10M iterations, and 2. The function is a "probably IPv4" heuristic, not a proper validator. PR-URL: https://github.com/nodejs/node/pull/18398 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jan Krems <jan.krems@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
This commit is contained in:
parent
1598ec73df
commit
742ae6141c
27
lib/dns.js
27
lib/dns.js
@ -24,7 +24,7 @@
|
|||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
const cares = process.binding('cares_wrap');
|
const cares = process.binding('cares_wrap');
|
||||||
const { isLegalPort } = require('internal/net');
|
const { isIP, isIPv4, isLegalPort } = require('internal/net');
|
||||||
const { customPromisifyArgs } = require('internal/util');
|
const { customPromisifyArgs } = require('internal/util');
|
||||||
const errors = require('internal/errors');
|
const errors = require('internal/errors');
|
||||||
const {
|
const {
|
||||||
@ -38,7 +38,6 @@ const {
|
|||||||
GetNameInfoReqWrap,
|
GetNameInfoReqWrap,
|
||||||
QueryReqWrap,
|
QueryReqWrap,
|
||||||
ChannelWrap,
|
ChannelWrap,
|
||||||
isIP
|
|
||||||
} = cares;
|
} = cares;
|
||||||
|
|
||||||
function errnoException(err, syscall, hostname) {
|
function errnoException(err, syscall, hostname) {
|
||||||
@ -66,30 +65,6 @@ function errnoException(err, syscall, hostname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const IANA_DNS_PORT = 53;
|
const IANA_DNS_PORT = 53;
|
||||||
const digits = [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48-63
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-79
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-95
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 112-127
|
|
||||||
];
|
|
||||||
function isIPv4(str) {
|
|
||||||
if (!digits[str.charCodeAt(0)]) return false;
|
|
||||||
if (str.length === 1) return false;
|
|
||||||
if (str.charCodeAt(1) === 46/*'.'*/)
|
|
||||||
return true;
|
|
||||||
else if (!digits[str.charCodeAt(1)])
|
|
||||||
return false;
|
|
||||||
if (str.length === 2) return false;
|
|
||||||
if (str.charCodeAt(2) === 46/*'.'*/)
|
|
||||||
return true;
|
|
||||||
else if (!digits[str.charCodeAt(2)])
|
|
||||||
return false;
|
|
||||||
return (str.length > 3 && str.charCodeAt(3) === 46/*'.'*/);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function onlookup(err, addresses) {
|
function onlookup(err, addresses) {
|
||||||
|
@ -1,8 +1,22 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Buffer = require('buffer').Buffer;
|
const Buffer = require('buffer').Buffer;
|
||||||
|
const { isIPv6 } = process.binding('cares_wrap');
|
||||||
const { writeBuffer } = process.binding('fs');
|
const { writeBuffer } = process.binding('fs');
|
||||||
|
|
||||||
|
const octet = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
|
||||||
|
const re = new RegExp(`^${octet}[.]${octet}[.]${octet}[.]${octet}$`);
|
||||||
|
|
||||||
|
function isIPv4(s) {
|
||||||
|
return re.test(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIP(s) {
|
||||||
|
if (isIPv4(s)) return 4;
|
||||||
|
if (isIPv6(s)) return 6;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the port number is not NaN when coerced to a number,
|
// Check that the port number is not NaN when coerced to a number,
|
||||||
// is an integer and that it falls within the legal range of port numbers.
|
// is an integer and that it falls within the legal range of port numbers.
|
||||||
function isLegalPort(port) {
|
function isLegalPort(port) {
|
||||||
@ -33,6 +47,9 @@ function makeSyncWrite(fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
isIP,
|
||||||
|
isIPv4,
|
||||||
|
isIPv6,
|
||||||
isLegalPort,
|
isLegalPort,
|
||||||
makeSyncWrite,
|
makeSyncWrite,
|
||||||
normalizedArgsSymbol: Symbol('normalizedArgs')
|
normalizedArgsSymbol: Symbol('normalizedArgs')
|
||||||
|
14
lib/net.js
14
lib/net.js
@ -26,12 +26,14 @@ const stream = require('stream');
|
|||||||
const util = require('util');
|
const util = require('util');
|
||||||
const internalUtil = require('internal/util');
|
const internalUtil = require('internal/util');
|
||||||
const {
|
const {
|
||||||
|
isIP,
|
||||||
|
isIPv4,
|
||||||
|
isIPv6,
|
||||||
isLegalPort,
|
isLegalPort,
|
||||||
normalizedArgsSymbol,
|
normalizedArgsSymbol,
|
||||||
makeSyncWrite
|
makeSyncWrite
|
||||||
} = require('internal/net');
|
} = require('internal/net');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const cares = process.binding('cares_wrap');
|
|
||||||
const {
|
const {
|
||||||
UV_EADDRINUSE,
|
UV_EADDRINUSE,
|
||||||
UV_EINVAL,
|
UV_EINVAL,
|
||||||
@ -1066,7 +1068,7 @@ function lookupAndConnect(self, options) {
|
|||||||
var localAddress = options.localAddress;
|
var localAddress = options.localAddress;
|
||||||
var localPort = options.localPort;
|
var localPort = options.localPort;
|
||||||
|
|
||||||
if (localAddress && !cares.isIP(localAddress)) {
|
if (localAddress && !isIP(localAddress)) {
|
||||||
throw new errors.TypeError('ERR_INVALID_IP_ADDRESS', localAddress);
|
throw new errors.TypeError('ERR_INVALID_IP_ADDRESS', localAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1091,7 +1093,7 @@ function lookupAndConnect(self, options) {
|
|||||||
port |= 0;
|
port |= 0;
|
||||||
|
|
||||||
// If host is an IP, skip performing a lookup
|
// If host is an IP, skip performing a lookup
|
||||||
var addressType = cares.isIP(host);
|
var addressType = isIP(host);
|
||||||
if (addressType) {
|
if (addressType) {
|
||||||
nextTick(self[async_id_symbol], function() {
|
nextTick(self[async_id_symbol], function() {
|
||||||
if (self.connecting)
|
if (self.connecting)
|
||||||
@ -1775,9 +1777,9 @@ module.exports = {
|
|||||||
connect,
|
connect,
|
||||||
createConnection: connect,
|
createConnection: connect,
|
||||||
createServer,
|
createServer,
|
||||||
isIP: cares.isIP,
|
isIP: isIP,
|
||||||
isIPv4: cares.isIPv4,
|
isIPv4: isIPv4,
|
||||||
isIPv6: cares.isIPv6,
|
isIPv6: isIPv6,
|
||||||
Server,
|
Server,
|
||||||
Socket,
|
Socket,
|
||||||
Stream: Socket, // Legacy naming
|
Stream: Socket, // Legacy naming
|
||||||
|
@ -1886,16 +1886,6 @@ int ParseIP(const char* ip, ParseIPResult* result = nullptr) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsIP(const FunctionCallbackInfo<Value>& args) {
|
|
||||||
node::Utf8Value ip(args.GetIsolate(), args[0]);
|
|
||||||
args.GetReturnValue().Set(ParseIP(*ip));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsIPv4(const FunctionCallbackInfo<Value>& args) {
|
|
||||||
node::Utf8Value ip(args.GetIsolate(), args[0]);
|
|
||||||
args.GetReturnValue().Set(4 == ParseIP(*ip));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsIPv6(const FunctionCallbackInfo<Value>& args) {
|
void IsIPv6(const FunctionCallbackInfo<Value>& args) {
|
||||||
node::Utf8Value ip(args.GetIsolate(), args[0]);
|
node::Utf8Value ip(args.GetIsolate(), args[0]);
|
||||||
args.GetReturnValue().Set(6 == ParseIP(*ip));
|
args.GetReturnValue().Set(6 == ParseIP(*ip));
|
||||||
@ -2138,8 +2128,6 @@ void Initialize(Local<Object> target,
|
|||||||
|
|
||||||
env->SetMethod(target, "getaddrinfo", GetAddrInfo);
|
env->SetMethod(target, "getaddrinfo", GetAddrInfo);
|
||||||
env->SetMethod(target, "getnameinfo", GetNameInfo);
|
env->SetMethod(target, "getnameinfo", GetNameInfo);
|
||||||
env->SetMethod(target, "isIP", IsIP);
|
|
||||||
env->SetMethod(target, "isIPv4", IsIPv4);
|
|
||||||
env->SetMethod(target, "isIPv6", IsIPv6);
|
env->SetMethod(target, "isIPv6", IsIPv6);
|
||||||
env->SetMethod(target, "canonicalizeIP", CanonicalizeIP);
|
env->SetMethod(target, "canonicalizeIP", CanonicalizeIP);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user