summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2009-09-30 15:49:22 -0700
committerLorenzo Colitti <lorenzo@google.com>2009-09-30 16:29:48 -0700
commite325918715987b5efc5cbb80271be467878aeebd (patch)
treed4337fe876b893d733884821845e94d08dccbb78 /luni
parent72d9339c03709c6f9c85b55297ada12f46586512 (diff)
downloadlibcore-e325918715987b5efc5cbb80271be467878aeebd.zip
libcore-e325918715987b5efc5cbb80271be467878aeebd.tar.gz
libcore-e325918715987b5efc5cbb80271be467878aeebd.tar.bz2
Fixes for socket options on multicast sockets.
1. Properly pass get/setsockopt the pointer to the socket option instead of the pointer to the pointer to the option. This was not caught at compile time because it's a void *. 2. Handle IPv4 multicast addresses on IPv6 sockets. This is important because current devices create IPv6 sockets by default. 3. Use the proper options for IPv6 multicast (i.e., IPV6_{ADD,DROP}_MEMBERSHIP instead of IP_{ADD,DROP}_MEMBERSHIP) 4. Use integers instead of bytes when getting or setting the multicast TTL because that's what the Linux kernel uses. These fix 10 of the 11 MulticastSocketTest failures. Also, minor changes: 1. Add ifdefd-out logging functions for get/setsockopt. 2. Change all instances of IPPROTO_{IP,IPv6} to SOL_{IP,IPV6} in get/setsockopt calls. Even though the values are the same (so the code worked), this way is more correct. Change-Id: Iea75a523d7e71f0b361a42c0e39d3ef075dc7ff4
Diffstat (limited to 'luni')
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp93
1 files changed, 72 insertions, 21 deletions
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index ac2b4e2..339c62c 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -1320,6 +1320,24 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
}
+#if LOG_SOCKOPT
+/**
+ * Helper method to log getsockopt/getsockopt calls.
+ */
+static const char *sockoptLevelToString(int level) {
+ switch(level) {
+ case SOL_SOCKET:
+ return "SOL_SOCKET";
+ case SOL_IP:
+ return "SOL_IP";
+ case SOL_IPV6:
+ return "SOL_IPV6";
+ default:
+ return "SOL_???";
+ }
+}
+#endif
+
/**
* Helper method to get or set socket options
*
@@ -1342,25 +1360,42 @@ static int getOrSetSocketOption(int action, int socket, int ipv4Option,
switch (family) {
case AF_INET:
option = ipv4Option;
- protocol = IPPROTO_IP;
+ protocol = SOL_IP;
break;
case AF_INET6:
option = ipv6Option;
- protocol = IPPROTO_IPV6;
+ protocol = SOL_IPV6;
break;
default:
+ // TODO: throw Java exceptions from this method instead of just
+ // returning error codes.
errno = EAFNOSUPPORT;
return -1;
}
+
+ int ret;
if (action == SOCKOPT_GET) {
- return getsockopt(socket, protocol, option, &optionValue, optionLength);
+ ret = getsockopt(socket, protocol, option, optionValue, optionLength);
+#if LOG_SOCKOPT
+ LOGI("getsockopt(%d, %s, %d, %p, [%d]) = %d %s",
+ socket, sockoptLevelToString(protocol), option, optionValue,
+ *optionLength, ret, (ret == -1) ? strerror(errno) : "");
+#endif
} else if (action == SOCKOPT_SET) {
- return setsockopt(socket, protocol, option, &optionValue,
- *optionLength);
+ ret = setsockopt(socket, protocol, option, optionValue, *optionLength);
+#if LOG_SOCKOPT
+ LOGI("setsockopt(%d, %s, %d, [%d], %d) = %d %s",
+ socket, sockoptLevelToString(protocol), option,
+ // Note: this only works for integer options.
+ // TODO: Use dvmPrintHexDump() to log non-integer options.
+ *(int *)optionValue, *optionLength, ret,
+ (ret == -1) ? strerror(errno) : "");
+#endif
} else {
errno = EINVAL;
- return -1;
+ ret = -1;
}
+ return ret;
}
/*
@@ -1382,13 +1417,13 @@ static int interfaceIndexFromMulticastSocket(int socket) {
// IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
struct ip_mreqn tempRequest;
requestLength = sizeof(tempRequest);
- result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
+ result = getsockopt(socket, SOL_IP, IP_MULTICAST_IF, &tempRequest,
&requestLength);
interfaceIndex = tempRequest.imr_ifindex;
} else if (family == AF_INET6) {
// IPV6_MULTICAST_IF returns a pointer to an integer.
requestLength = sizeof(interfaceIndex);
- result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ result = getsockopt(socket, SOL_IPV6, IPV6_MULTICAST_IF,
&interfaceIndex, &requestLength);
} else {
errno = EAFNOSUPPORT;
@@ -1465,7 +1500,7 @@ static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
multicastRequest.imr_multiaddr = sin->sin_addr;
- result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
+ result = setsockopt(handle, SOL_IP, setSockOptVal,
&multicastRequest, length);
if (0 != result) {
throwSocketException (env, convertError(errno));
@@ -1497,12 +1532,18 @@ static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
if (result < 0) // Exception has already been thrown.
return;
+ int family = getSocketAddressFamily(handle);
+
+ // Handle IPv4 multicast on an IPv6 socket.
+ if (family == AF_INET6 && sockaddrP.ss_family == AF_INET) {
+ family = AF_INET;
+ }
+
struct ip_mreqn ipv4Request;
struct ipv6_mreq ipv6Request;
void *multicastRequest;
socklen_t requestLength;
int level;
- int family = getSocketAddressFamily(handle);
switch (family) {
case AF_INET:
requestLength = sizeof(ipv4Request);
@@ -1511,16 +1552,23 @@ static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
((struct sockaddr_in *) &sockaddrP)->sin_addr;
ipv4Request.imr_ifindex = interfaceIndex;
multicastRequest = &ipv4Request;
- level = IPPROTO_IP;
+ level = SOL_IP;
break;
case AF_INET6:
+ // setSockOptVal is passed in by the caller and may be IPv4-only
+ if (setSockOptVal == IP_ADD_MEMBERSHIP) {
+ setSockOptVal = IPV6_ADD_MEMBERSHIP;
+ }
+ if (setSockOptVal == IP_DROP_MEMBERSHIP) {
+ setSockOptVal == IPV6_DROP_MEMBERSHIP;
+ }
requestLength = sizeof(ipv6Request);
memset(&ipv6Request, 0, requestLength);
ipv6Request.ipv6mr_multiaddr =
((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
ipv6Request.ipv6mr_interface = interfaceIndex;
multicastRequest = &ipv6Request;
- level = IPPROTO_IPV6;
+ level = SOL_IPV6;
break;
default:
throwSocketException (env, SOCKERR_BADAF);
@@ -3032,20 +3080,21 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return newJavaLangByte(env, 0);
}
+ // Java uses a byte to store the TTL, but the kernel uses an int.
result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
- IPV6_MULTICAST_HOPS, &byteValue,
- &byteSize);
+ IPV6_MULTICAST_HOPS, &intValue,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
}
- return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
+ return newJavaLangByte(env, (jbyte)(intValue & 0xFF));
}
case JAVASOCKOPT_MCAST_INTERFACE: {
if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
return NULL;
}
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
+ result = getsockopt(handle, SOL_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -3065,14 +3114,14 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
switch (addressFamily) {
case AF_INET:
optionLength = sizeof(multicastRequest);
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+ result = getsockopt(handle, SOL_IP, IP_MULTICAST_IF,
&multicastRequest, &optionLength);
if (result == 0)
interfaceIndex = multicastRequest.imr_ifindex;
break;
case AF_INET6:
optionLength = sizeof(interfaceIndex);
- result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ result = getsockopt(handle, SOL_IPV6, IPV6_MULTICAST_IF,
&interfaceIndex, &optionLength);
break;
default:
@@ -3239,9 +3288,11 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return;
}
+ // Java uses a byte to store the TTL, but the kernel uses an int.
+ intVal = byteVal;
result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
- IPV6_MULTICAST_HOPS, &byteVal,
- &byteSize);
+ IPV6_MULTICAST_HOPS, &intVal,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3274,7 +3325,7 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
memset(&mcast_req, 0, sizeof(mcast_req));
struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
mcast_req.imr_address = sin->sin_addr;
- result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+ result = setsockopt(handle, SOL_IP, IP_MULTICAST_IF,
&mcast_req, sizeof(mcast_req));
if (0 != result) {
throwSocketException(env, convertError(errno));