am 761e39e1: Merge "Switch to using android.system.Os for more calls"

* commit '761e39e18990b657c488c78a6c048f625bd6b74a':
  Switch to using android.system.Os for more calls
This commit is contained in:
Neil Fuller
2015-07-03 14:18:36 +00:00
committed by Android Git Automerger
2 changed files with 90 additions and 239 deletions

View File

@@ -25,6 +25,8 @@ import java.net.SocketOptions;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.system.OsConstants; import android.system.OsConstants;
import android.system.StructLinger;
import android.system.StructTimeval;
/** /**
* Socket implementation used for android.net.LocalSocket and * Socket implementation used for android.net.LocalSocket and
@@ -184,13 +186,6 @@ class LocalSocketImpl
private native void shutdown(FileDescriptor fd, boolean shutdownInput); private native void shutdown(FileDescriptor fd, boolean shutdownInput);
private native Credentials getPeerCredentials_native( private native Credentials getPeerCredentials_native(
FileDescriptor fd) throws IOException; 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. * Accepts a connection on a server socket.
@@ -232,7 +227,7 @@ class LocalSocketImpl
* or {@link LocalSocket#SOCKET_SEQPACKET} * or {@link LocalSocket#SOCKET_SEQPACKET}
* @throws IOException * @throws IOException
*/ */
public void create (int sockType) throws IOException { public void create(int sockType) throws IOException {
// no error if socket already created // no error if socket already created
// need this for LocalServerSocket.accept() // need this for LocalServerSocket.accept()
if (fd == null) { if (fd == null) {
@@ -434,24 +429,49 @@ class LocalSocketImpl
throw new IOException("socket not created"); throw new IOException("socket not created");
} }
if (optID == SocketOptions.SO_TIMEOUT) { try {
return 0; Object toReturn;
} switch (optID) {
case SocketOptions.SO_TIMEOUT:
int value = getOption_native(fd, optID); StructTimeval timeval = Os.getsockoptTimeval(fd, OsConstants.SOL_SOCKET,
switch (optID) OsConstants.SO_SNDTIMEO);
{ toReturn = (int) timeval.toMillis();
case SocketOptions.SO_RCVBUF: break;
case SocketOptions.SO_SNDBUF: case SocketOptions.SO_RCVBUF:
return value; case SocketOptions.SO_SNDBUF:
case SocketOptions.SO_REUSEADDR: case SocketOptions.SO_REUSEADDR:
default: int osOpt = javaSoToOsOpt(optID);
return value; 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) public void setOption(int optID, Object value)
throws IOException { throws IOException {
if (fd == null) {
throw new IOException("socket not created");
}
/* /*
* Boolean.FALSE is used to disable some options, so it * Boolean.FALSE is used to disable some options, so it
* is important to distinguish between FALSE and unset. * is important to distinguish between FALSE and unset.
@@ -460,11 +480,6 @@ class LocalSocketImpl
*/ */
int boolValue = -1; int boolValue = -1;
int intValue = 0; int intValue = 0;
if (fd == null) {
throw new IOException("socket not created");
}
if (value instanceof Integer) { if (value instanceof Integer) {
intValue = (Integer)value; intValue = (Integer)value;
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
@@ -473,7 +488,39 @@ class LocalSocketImpl
throw new IOException("bad value: " + value); 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 * @return non-null; peer credentials
* @throws IOException * @throws IOException
*/ */
public Credentials getPeerCredentials() throws IOException public Credentials getPeerCredentials() throws IOException {
{
return getPeerCredentials_native(fd); return getPeerCredentials_native(fd);
} }
@@ -528,15 +574,26 @@ class LocalSocketImpl
* @return non-null; socket name * @return non-null; socket name
* @throws IOException on failure * @throws IOException on failure
*/ */
public LocalSocketAddress getSockAddress() throws IOException public LocalSocketAddress getSockAddress() throws IOException {
{ // This method has never been implemented.
return null; return null;
//TODO implement this
//return getSockName_native(fd);
} }
@Override @Override
protected void finalize() throws IOException { protected void finalize() throws IOException {
close(); 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);
}
}
} }

View File

@@ -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, static jint socket_pending (JNIEnv *env, jobject object,
jobject fileDescriptor) jobject fileDescriptor)
{ {
@@ -803,64 +653,11 @@ static jobject socket_get_peer_credentials(JNIEnv *env,
creds.pid, creds.uid, creds.gid); 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. * JNI registration.
*/ */
static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */ /* 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", {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
(void*)socket_connect_local}, (void*)socket_connect_local},
{"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local}, {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
@@ -876,9 +673,6 @@ static JNINativeMethod gMethods[] = {
{"getPeerCredentials_native", {"getPeerCredentials_native",
"(Ljava/io/FileDescriptor;)Landroid/net/Credentials;", "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
(void*) socket_get_peer_credentials} (void*) socket_get_peer_credentials}
//,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
// (void *) socket_getSockName}
}; };
int register_android_net_LocalSocketImpl(JNIEnv *env) int register_android_net_LocalSocketImpl(JNIEnv *env)