[#2867] Workaround performance issue with IPv4-mapped-on-IPv6 addresses
Motivation: InetAddress.getByName(...) uses exceptions for control flow when try to parse IPv4-mapped-on-IPv6 addresses. This is quite expensive. Modifications: Detect IPv4-mapped-on-IPv6 addresses in the JNI level and convert to IPv4 addresses before pass to InetAddress.getByName(...) (via InetSocketAddress constructor). Result: Eliminate performance problem causes by exception creation when parsing IPv4-mapped-on-IPv6 addresses.
This commit is contained in:
parent
ec604a3464
commit
7e48801f71
@ -55,6 +55,7 @@ jclass inetSocketAddressClass = NULL;
|
|||||||
jclass datagramSocketAddressClass = NULL;
|
jclass datagramSocketAddressClass = NULL;
|
||||||
|
|
||||||
static int socketType;
|
static int socketType;
|
||||||
|
static const char *ip4prefix = "::ffff:";
|
||||||
|
|
||||||
// util methods
|
// util methods
|
||||||
void throwRuntimeException(JNIEnv *env, char *message) {
|
void throwRuntimeException(JNIEnv *env, char *message) {
|
||||||
@ -128,16 +129,27 @@ int setOption(JNIEnv *env, jint fd, int level, int optname, const void *optval,
|
|||||||
jobject createInetSocketAddress(JNIEnv * env, struct sockaddr_storage addr) {
|
jobject createInetSocketAddress(JNIEnv * env, struct sockaddr_storage addr) {
|
||||||
char ipstr[INET6_ADDRSTRLEN];
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
int port;
|
int port;
|
||||||
|
jstring ipString;
|
||||||
if (addr.ss_family == AF_INET) {
|
if (addr.ss_family == AF_INET) {
|
||||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||||
port = ntohs(s->sin_port);
|
port = ntohs(s->sin_port);
|
||||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||||
port = ntohs(s->sin6_port);
|
port = ntohs(s->sin6_port);
|
||||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||||
|
if (strncasecmp(ipstr, ip4prefix, 7) == 0) {
|
||||||
|
// IPv4-mapped-on-IPv6.
|
||||||
|
// Cut of ::ffff: prefix to workaround performance issues when parsing these
|
||||||
|
// addresses in InetAddress.getByName(...).
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/2867
|
||||||
|
ipString = (*env)->NewStringUTF(env, &ipstr[7]);
|
||||||
|
} else {
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
jstring ipString = (*env)->NewStringUTF(env, ipstr);
|
|
||||||
jobject socketAddr = (*env)->NewObject(env, inetSocketAddressClass, inetSocketAddrMethodId, ipString, port);
|
jobject socketAddr = (*env)->NewObject(env, inetSocketAddressClass, inetSocketAddrMethodId, ipString, port);
|
||||||
return socketAddr;
|
return socketAddr;
|
||||||
}
|
}
|
||||||
@ -145,16 +157,28 @@ jobject createInetSocketAddress(JNIEnv * env, struct sockaddr_storage addr) {
|
|||||||
jobject createDatagramSocketAddress(JNIEnv * env, struct sockaddr_storage addr, int len) {
|
jobject createDatagramSocketAddress(JNIEnv * env, struct sockaddr_storage addr, int len) {
|
||||||
char ipstr[INET6_ADDRSTRLEN];
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
int port;
|
int port;
|
||||||
|
jstring ipString;
|
||||||
if (addr.ss_family == AF_INET) {
|
if (addr.ss_family == AF_INET) {
|
||||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||||
port = ntohs(s->sin_port);
|
port = ntohs(s->sin_port);
|
||||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||||
port = ntohs(s->sin6_port);
|
port = ntohs(s->sin6_port);
|
||||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||||
|
|
||||||
|
if (strncasecmp(ipstr, ip4prefix, 7) == 0) {
|
||||||
|
// IPv4-mapped-on-IPv6.
|
||||||
|
// Cut of ::ffff: prefix to workaround performance issues when parsing these
|
||||||
|
// addresses in InetAddress.getByName(...).
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/2867
|
||||||
|
ipString = (*env)->NewStringUTF(env, &ipstr[7]);
|
||||||
|
} else {
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
jstring ipString = (*env)->NewStringUTF(env, ipstr);
|
|
||||||
jobject socketAddr = (*env)->NewObject(env, datagramSocketAddressClass, datagramSocketAddrMethodId, ipString, port, len);
|
jobject socketAddr = (*env)->NewObject(env, datagramSocketAddressClass, datagramSocketAddrMethodId, ipString, port, len);
|
||||||
return socketAddr;
|
return socketAddr;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user