[#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:
Norman Maurer 2014-09-07 13:38:00 +02:00
parent 4e62b51c6d
commit cb1bf1a74e

View File

@ -55,6 +55,7 @@ jclass inetSocketAddressClass = NULL;
jclass datagramSocketAddressClass = NULL;
static int socketType;
static const char *ip4prefix = "::ffff:";
// util methods
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) {
char ipstr[INET6_ADDRSTRLEN];
int port;
jstring ipString;
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
ipString = (*env)->NewStringUTF(env, ipstr);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
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);
return socketAddr;
}
@ -145,16 +157,28 @@ jobject createInetSocketAddress(JNIEnv * env, struct sockaddr_storage addr) {
jobject createDatagramSocketAddress(JNIEnv * env, struct sockaddr_storage addr, int len) {
char ipstr[INET6_ADDRSTRLEN];
int port;
jstring ipString;
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
ipString = (*env)->NewStringUTF(env, ipstr);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
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);
return socketAddr;
}