Switch to using android.system.Os for more calls
The methods being switched here should involve no important
semantic changes. socket.getSoTimeout() is now implemented:
previously it would have returned 0 in all cases.
Some tidy up of unimplemented / commented code.
Switching other calls to use Os would carry more risk and
will be handled separately they can be switched safely.
Bug: 3106438
Change-Id: I5526249395565fee6e43f159a2b5975b0d41d058
This commit is contained in:
@@ -25,6 +25,8 @@ import java.net.SocketOptions;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.system.StructLinger;
|
||||
import android.system.StructTimeval;
|
||||
|
||||
/**
|
||||
* Socket implementation used for android.net.LocalSocket and
|
||||
@@ -184,13 +186,6 @@ class LocalSocketImpl
|
||||
private native void shutdown(FileDescriptor fd, boolean shutdownInput);
|
||||
private native Credentials getPeerCredentials_native(
|
||||
FileDescriptor fd) throws IOException;
|
||||
private native int getOption_native(FileDescriptor fd, int optID)
|
||||
throws IOException;
|
||||
private native void setOption_native(FileDescriptor fd, int optID,
|
||||
int b, int value) throws IOException;
|
||||
|
||||
// private native LocalSocketAddress getSockName_native
|
||||
// (FileDescriptor fd) throws IOException;
|
||||
|
||||
/**
|
||||
* Accepts a connection on a server socket.
|
||||
@@ -232,7 +227,7 @@ class LocalSocketImpl
|
||||
* or {@link LocalSocket#SOCKET_SEQPACKET}
|
||||
* @throws IOException
|
||||
*/
|
||||
public void create (int sockType) throws IOException {
|
||||
public void create(int sockType) throws IOException {
|
||||
// no error if socket already created
|
||||
// need this for LocalServerSocket.accept()
|
||||
if (fd == null) {
|
||||
@@ -434,24 +429,49 @@ class LocalSocketImpl
|
||||
throw new IOException("socket not created");
|
||||
}
|
||||
|
||||
if (optID == SocketOptions.SO_TIMEOUT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int value = getOption_native(fd, optID);
|
||||
switch (optID)
|
||||
{
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
return value;
|
||||
case SocketOptions.SO_REUSEADDR:
|
||||
default:
|
||||
return value;
|
||||
try {
|
||||
Object toReturn;
|
||||
switch (optID) {
|
||||
case SocketOptions.SO_TIMEOUT:
|
||||
StructTimeval timeval = Os.getsockoptTimeval(fd, OsConstants.SOL_SOCKET,
|
||||
OsConstants.SO_SNDTIMEO);
|
||||
toReturn = (int) timeval.toMillis();
|
||||
break;
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
case SocketOptions.SO_REUSEADDR:
|
||||
int osOpt = javaSoToOsOpt(optID);
|
||||
toReturn = Os.getsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt);
|
||||
break;
|
||||
case SocketOptions.SO_LINGER:
|
||||
StructLinger linger=
|
||||
Os.getsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER);
|
||||
if (!linger.isOn()) {
|
||||
toReturn = -1;
|
||||
} else {
|
||||
toReturn = linger.l_linger;
|
||||
}
|
||||
break;
|
||||
case SocketOptions.TCP_NODELAY:
|
||||
toReturn = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
|
||||
OsConstants.TCP_NODELAY);
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown option: " + optID);
|
||||
}
|
||||
return toReturn;
|
||||
} catch (ErrnoException e) {
|
||||
throw e.rethrowAsIOException();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOption(int optID, Object value)
|
||||
throws IOException {
|
||||
|
||||
if (fd == null) {
|
||||
throw new IOException("socket not created");
|
||||
}
|
||||
|
||||
/*
|
||||
* Boolean.FALSE is used to disable some options, so it
|
||||
* is important to distinguish between FALSE and unset.
|
||||
@@ -460,11 +480,6 @@ class LocalSocketImpl
|
||||
*/
|
||||
int boolValue = -1;
|
||||
int intValue = 0;
|
||||
|
||||
if (fd == null) {
|
||||
throw new IOException("socket not created");
|
||||
}
|
||||
|
||||
if (value instanceof Integer) {
|
||||
intValue = (Integer)value;
|
||||
} else if (value instanceof Boolean) {
|
||||
@@ -473,7 +488,39 @@ class LocalSocketImpl
|
||||
throw new IOException("bad value: " + value);
|
||||
}
|
||||
|
||||
setOption_native(fd, optID, boolValue, intValue);
|
||||
try {
|
||||
switch (optID) {
|
||||
case SocketOptions.SO_LINGER:
|
||||
StructLinger linger = new StructLinger(boolValue, intValue);
|
||||
Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
|
||||
break;
|
||||
case SocketOptions.SO_TIMEOUT:
|
||||
/*
|
||||
* SO_TIMEOUT from the core library gets converted to
|
||||
* SO_SNDTIMEO, but the option is supposed to set both
|
||||
* send and receive timeouts. Note: The incoming timeout
|
||||
* value is in milliseconds.
|
||||
*/
|
||||
StructTimeval timeval = StructTimeval.fromMillis(intValue);
|
||||
Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
|
||||
timeval);
|
||||
break;
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
case SocketOptions.SO_REUSEADDR:
|
||||
int osOpt = javaSoToOsOpt(optID);
|
||||
Os.setsockoptInt(fd, OsConstants.SOL_SOCKET, osOpt, intValue);
|
||||
break;
|
||||
case SocketOptions.TCP_NODELAY:
|
||||
Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_NODELAY,
|
||||
intValue);
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown option: " + optID);
|
||||
}
|
||||
} catch (ErrnoException e) {
|
||||
throw e.rethrowAsIOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,8 +564,7 @@ class LocalSocketImpl
|
||||
* @return non-null; peer credentials
|
||||
* @throws IOException
|
||||
*/
|
||||
public Credentials getPeerCredentials() throws IOException
|
||||
{
|
||||
public Credentials getPeerCredentials() throws IOException {
|
||||
return getPeerCredentials_native(fd);
|
||||
}
|
||||
|
||||
@@ -528,15 +574,26 @@ class LocalSocketImpl
|
||||
* @return non-null; socket name
|
||||
* @throws IOException on failure
|
||||
*/
|
||||
public LocalSocketAddress getSockAddress() throws IOException
|
||||
{
|
||||
public LocalSocketAddress getSockAddress() throws IOException {
|
||||
// This method has never been implemented.
|
||||
return null;
|
||||
//TODO implement this
|
||||
//return getSockName_native(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws IOException {
|
||||
close();
|
||||
}
|
||||
|
||||
private static int javaSoToOsOpt(int optID) {
|
||||
switch (optID) {
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
return OsConstants.SO_SNDBUF;
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
return OsConstants.SO_RCVBUF;
|
||||
case SocketOptions.SO_REUSEADDR:
|
||||
return OsConstants.SO_REUSEADDR;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown option: " + optID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,156 +199,6 @@ socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor,
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
java_opt_to_real(int optID, int* opt, int* level)
|
||||
{
|
||||
switch (optID)
|
||||
{
|
||||
case 4098:
|
||||
*opt = SO_RCVBUF;
|
||||
*level = SOL_SOCKET;
|
||||
return true;
|
||||
case 4097:
|
||||
*opt = SO_SNDBUF;
|
||||
*level = SOL_SOCKET;
|
||||
return true;
|
||||
case 4102:
|
||||
*opt = SO_SNDTIMEO;
|
||||
*level = SOL_SOCKET;
|
||||
return true;
|
||||
case 128:
|
||||
*opt = SO_LINGER;
|
||||
*level = SOL_SOCKET;
|
||||
return true;
|
||||
case 1:
|
||||
*opt = TCP_NODELAY;
|
||||
*level = IPPROTO_TCP;
|
||||
return true;
|
||||
case 4:
|
||||
*opt = SO_REUSEADDR;
|
||||
*level = SOL_SOCKET;
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static jint
|
||||
socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, jint optID)
|
||||
{
|
||||
int ret, value;
|
||||
int opt, level;
|
||||
int fd;
|
||||
|
||||
socklen_t size = sizeof(int);
|
||||
|
||||
if (!java_opt_to_real(optID, &opt, &level)) {
|
||||
jniThrowIOException(env, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case SO_LINGER:
|
||||
{
|
||||
struct linger lingr;
|
||||
size = sizeof(lingr);
|
||||
ret = getsockopt(fd, level, opt, &lingr, &size);
|
||||
if (!lingr.l_onoff) {
|
||||
value = -1;
|
||||
} else {
|
||||
value = lingr.l_linger;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = getsockopt(fd, level, opt, &value, &size);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (ret != 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void socket_setOption(
|
||||
JNIEnv *env, jobject object, jobject fileDescriptor, jint optID,
|
||||
jint boolValue, jint intValue) {
|
||||
int ret;
|
||||
int optname;
|
||||
int level;
|
||||
int fd;
|
||||
|
||||
if (!java_opt_to_real(optID, &optname, &level)) {
|
||||
jniThrowIOException(env, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (optname) {
|
||||
case SO_LINGER: {
|
||||
/*
|
||||
* SO_LINGER is special because it needs to use a special
|
||||
* "linger" struct as well as use the incoming boolean
|
||||
* argument specially.
|
||||
*/
|
||||
struct linger lingr;
|
||||
lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
|
||||
lingr.l_linger = intValue;
|
||||
ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
|
||||
break;
|
||||
}
|
||||
case SO_SNDTIMEO: {
|
||||
/*
|
||||
* SO_TIMEOUT from the core library gets converted to
|
||||
* SO_SNDTIMEO, but the option is supposed to set both
|
||||
* send and receive timeouts. Note: The incoming timeout
|
||||
* value is in milliseconds.
|
||||
*/
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = intValue / 1000;
|
||||
timeout.tv_usec = (intValue % 1000) * 1000;
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
|
||||
(void *)&timeout, sizeof(timeout));
|
||||
|
||||
if (ret == 0) {
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
|
||||
(void *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/*
|
||||
* In all other cases, the translated option level and
|
||||
* optname may be used directly for a call to setsockopt().
|
||||
*/
|
||||
ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
static jint socket_pending (JNIEnv *env, jobject object,
|
||||
jobject fileDescriptor)
|
||||
{
|
||||
@@ -803,64 +653,11 @@ static jobject socket_get_peer_credentials(JNIEnv *env,
|
||||
creds.pid, creds.uid, creds.gid);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//TODO change this to return an instance of LocalSocketAddress
|
||||
static jobject socket_getSockName(JNIEnv *env,
|
||||
jobject object, jobject fileDescriptor)
|
||||
{
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (fileDescriptor == NULL) {
|
||||
jniThrowNullPointerException(env, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
union {
|
||||
struct sockaddr address;
|
||||
struct sockaddr_un un_address;
|
||||
} sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
|
||||
socklen_t namelen = sizeof(sa);
|
||||
err = getsockname(fd, &(sa.address), &namelen);
|
||||
|
||||
if (err < 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sa.address.sa_family != AF_UNIX) {
|
||||
// We think we're an impl only for AF_UNIX, so this should never happen.
|
||||
|
||||
jniThrowIOException(env, EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sa.un_address.sun_path[0] == '\0') {
|
||||
} else {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* JNI registration.
|
||||
*/
|
||||
static JNINativeMethod gMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
|
||||
{"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
|
||||
{"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
|
||||
(void*)socket_connect_local},
|
||||
{"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
|
||||
@@ -876,9 +673,6 @@ static JNINativeMethod gMethods[] = {
|
||||
{"getPeerCredentials_native",
|
||||
"(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
|
||||
(void*) socket_get_peer_credentials}
|
||||
//,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
|
||||
// (void *) socket_getSockName}
|
||||
|
||||
};
|
||||
|
||||
int register_android_net_LocalSocketImpl(JNIEnv *env)
|
||||
|
||||
Reference in New Issue
Block a user