diff options
Diffstat (limited to 'core/jni/android_bluetooth_RfcommSocket.cpp')
-rw-r--r-- | core/jni/android_bluetooth_RfcommSocket.cpp | 621 |
1 files changed, 0 insertions, 621 deletions
diff --git a/core/jni/android_bluetooth_RfcommSocket.cpp b/core/jni/android_bluetooth_RfcommSocket.cpp deleted file mode 100644 index 3ed35d9..0000000 --- a/core/jni/android_bluetooth_RfcommSocket.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define LOG_TAG "bluetooth_RfcommSocket.cpp" - -#include "android_bluetooth_common.h" -#include "android_runtime/AndroidRuntime.h" -#include "JNIHelp.h" -#include "jni.h" -#include "utils/Log.h" -#include "utils/misc.h" - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <sys/poll.h> - -#ifdef HAVE_BLUETOOTH -#include <bluetooth/bluetooth.h> -#include <bluetooth/rfcomm.h> -#include <bluetooth/sco.h> -#endif - -namespace android { - -#ifdef HAVE_BLUETOOTH -static jfieldID field_mNativeData; -static jfieldID field_mTimeoutRemainingMs; -static jfieldID field_mAcceptTimeoutRemainingMs; -static jfieldID field_mAddress; -static jfieldID field_mPort; - -typedef struct { - jstring address; - const char *c_address; - int rfcomm_channel; - int last_read_err; - int rfcomm_sock; - // < 0 -- in progress, - // 0 -- not connected - // > 0 connected - // 1 input is open - // 2 output is open - // 3 both input and output are open - int rfcomm_connected; - int rfcomm_sock_flags; -} native_data_t; - -static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { - return (native_data_t *)(env->GetIntField(object, field_mNativeData)); -} - -static inline void init_socket_info( - JNIEnv *env, jobject object, - native_data_t *nat, - jstring address, - jint rfcomm_channel) { - nat->address = (jstring)env->NewGlobalRef(address); - nat->c_address = env->GetStringUTFChars(nat->address, NULL); - nat->rfcomm_channel = (int)rfcomm_channel; -} - -static inline void cleanup_socket_info(JNIEnv *env, native_data_t *nat) { - if (nat->c_address != NULL) { - env->ReleaseStringUTFChars(nat->address, nat->c_address); - env->DeleteGlobalRef(nat->address); - nat->c_address = NULL; - } -} -#endif - -static void classInitNative(JNIEnv* env, jclass clazz) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - field_mNativeData = get_field(env, clazz, "mNativeData", "I"); - field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I"); - field_mAcceptTimeoutRemainingMs = get_field(env, clazz, "mAcceptTimeoutRemainingMs", "I"); - field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;"); - field_mPort = get_field(env, clazz, "mPort", "I"); -#endif -} - -static void initializeNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - - native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); - if (nat == NULL) { - LOGE("%s: out of memory!", __FUNCTION__); - return; - } - - env->SetIntField(object, field_mNativeData, (jint)nat); - nat->rfcomm_sock = -1; - nat->rfcomm_connected = 0; -#endif -} - -static void cleanupNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, object); - if (nat) { - free(nat); - } -#endif -} - -static jobject createNative(JNIEnv *env, jobject obj) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - int lm; - native_data_t *nat = get_native_data(env, obj); - nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__, - strerror(errno)); - return NULL; - } - - lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT; - - if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, - sizeof(lm)) < 0) { - LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__); - close(nat->rfcomm_sock); - return NULL; - } - - return jniCreateFileDescriptor(env, nat->rfcomm_sock); -#else - return NULL; -#endif -} - -static void destroyNative(JNIEnv *env, jobject obj) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - cleanup_socket_info(env, nat); - if (nat->rfcomm_sock >= 0) { - close(nat->rfcomm_sock); - nat->rfcomm_sock = -1; - } -#endif -} - - -static jboolean connectNative(JNIEnv *env, jobject obj, - jstring address, jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - - if (nat->rfcomm_sock >= 0) { - if (nat->rfcomm_connected) { - LOGI("RFCOMM socket: %s.", - (nat->rfcomm_connected > 0) ? "already connected" : "connection is in progress"); - return JNI_TRUE; - } - - init_socket_info(env, obj, nat, address, port); - - struct sockaddr_rc addr; - memset(&addr, 0, sizeof(struct sockaddr_rc)); - get_bdaddr(nat->c_address, &addr.rc_bdaddr); - addr.rc_channel = nat->rfcomm_channel; - addr.rc_family = AF_BLUETOOTH; - nat->rfcomm_connected = 0; - - while (nat->rfcomm_connected == 0) { - if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr, - sizeof(addr)) < 0) { - if (errno == EINTR) continue; - LOGE("connect error: %s (%d)\n", strerror(errno), errno); - break; - } else { - nat->rfcomm_connected = 3; // input and output - } - } - } else { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - } - - if (nat->rfcomm_connected > 0) { - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } -#endif - return JNI_FALSE; -} - -static jboolean connectAsyncNative(JNIEnv *env, jobject obj, - jstring address, jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - return JNI_FALSE; - } - - if (nat->rfcomm_connected) { - LOGI("RFCOMM socket: %s.", - (nat->rfcomm_connected > 0) ? - "already connected" : "connection is in progress"); - return JNI_TRUE; - } - - init_socket_info(env, obj, nat, address, port); - - struct sockaddr_rc addr; - memset(&addr, 0, sizeof(struct sockaddr_rc)); - get_bdaddr(nat->c_address, &addr.rc_bdaddr); - addr.rc_channel = nat->rfcomm_channel; - addr.rc_family = AF_BLUETOOTH; - - nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0); - if (fcntl(nat->rfcomm_sock, - F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) { - int rc; - nat->rfcomm_connected = 0; - errno = 0; - rc = connect(nat->rfcomm_sock, - (struct sockaddr *)&addr, - sizeof(addr)); - - if (rc >= 0) { - nat->rfcomm_connected = 3; - LOGI("RFCOMM async connect immediately successful"); - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } - else if (rc < 0) { - if (errno == EINPROGRESS || errno == EAGAIN) - { - LOGI("RFCOMM async connect is in progress (%s)", - strerror(errno)); - nat->rfcomm_connected = -1; - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } - else - { - LOGE("RFCOMM async connect error (%d): %s (%d)", - nat->rfcomm_sock, strerror(errno), errno); - return JNI_FALSE; - } - } - } // fcntl(nat->rfcomm_sock ...) -#endif - return JNI_FALSE; -} - -static jboolean interruptAsyncConnectNative(JNIEnv *env, jobject obj) { - //WRITEME - return JNI_TRUE; -} - -static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj, - jint timeout_ms) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - struct sockaddr_rc addr; - native_data_t *nat = get_native_data(env, obj); - - env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - return -1; - } - - if (nat->rfcomm_connected > 0) { - LOGI("%s: RFCOMM is already connected!", __FUNCTION__); - return 1; - } - - /* Do an asynchronous select() */ - int n; - fd_set rset, wset; - struct timeval to; - - FD_ZERO(&rset); - FD_ZERO(&wset); - FD_SET(nat->rfcomm_sock, &rset); - FD_SET(nat->rfcomm_sock, &wset); - if (timeout_ms >= 0) { - to.tv_sec = timeout_ms / 1000; - to.tv_usec = 1000 * (timeout_ms % 1000); - } - n = select(nat->rfcomm_sock + 1, - &rset, - &wset, - NULL, - (timeout_ms < 0 ? NULL : &to)); - - if (timeout_ms > 0) { - jint remaining = to.tv_sec*1000 + to.tv_usec/1000; - LOGI("Remaining time %ldms", (long)remaining); - env->SetIntField(obj, field_mTimeoutRemainingMs, - remaining); - } - - if (n <= 0) { - if (n < 0) { - LOGE("select() on RFCOMM socket: %s (%d)", - strerror(errno), - errno); - return -1; - } - return 0; - } - /* n must be equal to 1 and either rset or wset must have the - file descriptor set. */ - LOGI("select() returned %d.", n); - if (FD_ISSET(nat->rfcomm_sock, &rset) || - FD_ISSET(nat->rfcomm_sock, &wset)) { - /* A trial async read() will tell us if everything is OK. */ - char ch; - errno = 0; - int nr = read(nat->rfcomm_sock, &ch, 1); - /* It should be that nr != 1 because we just opened a socket - and we haven't sent anything over it for the other side to - respond... but one can't be paranoid enough. - */ - if (nr >= 0 || errno != EAGAIN) { - LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n", - strerror(errno), - errno, - nr); - /* Clear the rfcomm_connected flag to cause this function - to re-create the socket and re-attempt the connect() - the next time it is called. - */ - nat->rfcomm_connected = 0; - /* Restore the blocking properties of the socket. */ - fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags); - return -1; - } - /* Restore the blocking properties of the socket. */ - fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags); - LOGI("Successful RFCOMM socket connect."); - nat->rfcomm_connected = 3; // input and output - return 1; - } -#endif - return -1; -} - -static jboolean shutdownNative(JNIEnv *env, jobject obj, - jboolean shutdownInput) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - /* NOTE: If you change the bcode to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - int rc = shutdown(nat->rfcomm_sock, - shutdownInput ? SHUT_RD : SHUT_WR); - if (!rc) { - nat->rfcomm_connected &= - shutdownInput ? ~1 : ~2; - return JNI_TRUE; - } -#endif - return JNI_FALSE; -} - -static jint isConnectedNative(JNIEnv *env, jobject obj) { - LOGI(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - const native_data_t *nat = get_native_data(env, obj); - return nat->rfcomm_connected; -#endif - return 0; -} - -//@@@@@@@@@ bind to device??? -static jboolean bindNative(JNIEnv *env, jobject obj, jstring device, - jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - - /* NOTE: If you change the code to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - const native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - - struct sockaddr_rc laddr; - int lm; - - lm = 0; -/* - lm |= RFCOMM_LM_MASTER; - lm |= RFCOMM_LM_AUTH; - lm |= RFCOMM_LM_ENCRYPT; - lm |= RFCOMM_LM_SECURE; -*/ - - if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) { - LOGE("Can't set RFCOMM link mode"); - return JNI_FALSE; - } - - laddr.rc_family = AF_BLUETOOTH; - bacpy(&laddr.rc_bdaddr, BDADDR_ANY); - laddr.rc_channel = port; - - if (bind(nat->rfcomm_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { - LOGE("Can't bind RFCOMM socket"); - return JNI_FALSE; - } - - env->SetIntField(obj, field_mPort, port); - - return JNI_TRUE; -#endif - return JNI_FALSE; -} - -static jboolean listenNative(JNIEnv *env, jobject obj, jint backlog) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - /* NOTE: If you change the code to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - const native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - return listen(nat->rfcomm_sock, backlog) < 0 ? JNI_FALSE : JNI_TRUE; -#else - return JNI_FALSE; -#endif -} - -static int set_nb(int sk, bool nb) { - int flags = fcntl(sk, F_GETFL); - if (flags < 0) { - LOGE("Can't get socket flags with fcntl(): %s (%d)", - strerror(errno), errno); - close(sk); - return -1; - } - flags &= ~O_NONBLOCK; - if (nb) flags |= O_NONBLOCK; - int status = fcntl(sk, F_SETFL, flags); - if (status < 0) { - LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)", - strerror(errno), errno); - close(sk); - return -1; - } - return 0; -} - -// Note: the code should check at a higher level to see whether -// listen() has been called. -#ifdef HAVE_BLUETOOTH -static int do_accept(JNIEnv* env, jobject object, int sock, - jobject newsock, - jfieldID out_address, - bool must_succeed) { - - if (must_succeed && set_nb(sock, true) < 0) - return -1; - - struct sockaddr_rc raddr; - int alen = sizeof(raddr); - int nsk = accept(sock, (struct sockaddr *) &raddr, &alen); - if (nsk < 0) { - LOGE("Error on accept from socket fd %d: %s (%d).", - sock, - strerror(errno), - errno); - if (must_succeed) set_nb(sock, false); - return -1; - } - - char addr[BTADDR_SIZE]; - get_bdaddr_as_string(&raddr.rc_bdaddr, addr); - env->SetObjectField(newsock, out_address, env->NewStringUTF(addr)); - - LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d", - sock, - nsk, - addr, - raddr.rc_channel); - if (must_succeed) set_nb(sock, false); - return nsk; -} -#endif /*HAVE_BLUETOOTH*/ - -static jobject acceptNative(JNIEnv *env, jobject obj, - jobject newsock, jint timeoutMs) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - - if (newsock == NULL) { - LOGE("%s: newsock = NULL\n", __FUNCTION__); - return JNI_FALSE; - } - - int nsk = -1; - if (timeoutMs < 0) { - /* block until accept() succeeds */ - nsk = do_accept(env, obj, nat->rfcomm_sock, - newsock, field_mAddress, false); - if (nsk < 0) { - return NULL; - } - } - else { - /* wait with a timeout */ - - struct pollfd fds; - fds.fd = nat->rfcomm_sock; - fds.events = POLLIN | POLLPRI | POLLOUT | POLLERR; - - env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, 0); - int n = poll(&fds, 1, timeoutMs); - if (n <= 0) { - if (n < 0) { - LOGE("listening poll() on RFCOMM socket: %s (%d)", - strerror(errno), - errno); - env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, timeoutMs); - } - else { - LOGI("listening poll() on RFCOMM socket timed out"); - } - return NULL; - } - - LOGI("listening poll() on RFCOMM socket returned %d", n); - if (fds.fd == nat->rfcomm_sock) { - if (fds.revents & (POLLIN | POLLPRI | POLLOUT)) { - LOGI("Accepting connection.\n"); - nsk = do_accept(env, obj, nat->rfcomm_sock, - newsock, field_mAddress, true); - if (nsk < 0) { - return NULL; - } - } - } - } - - LOGI("Connection accepted, new socket fd = %d.", nsk); - native_data_t *newnat = get_native_data(env, newsock); - newnat->rfcomm_sock = nsk; - newnat->rfcomm_connected = 3; - return jniCreateFileDescriptor(env, nsk); -#else - return NULL; -#endif -} - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, - {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, - - {"createNative", "()Ljava/io/FileDescriptor;", (void *)createNative}, - {"destroyNative", "()V", (void *)destroyNative}, - {"connectNative", "(Ljava/lang/String;I)Z", (void *)connectNative}, - {"connectAsyncNative", "(Ljava/lang/String;I)Z", (void *)connectAsyncNative}, - {"interruptAsyncConnectNative", "()Z", (void *)interruptAsyncConnectNative}, - {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative}, - {"shutdownNative", "(Z)Z", (void *)shutdownNative}, - {"isConnectedNative", "()I", (void *)isConnectedNative}, - - {"bindNative", "(Ljava/lang/String;I)Z", (void*)bindNative}, - {"listenNative", "(I)Z", (void*)listenNative}, - {"acceptNative", "(Landroid/bluetooth/RfcommSocket;I)Ljava/io/FileDescriptor;", (void*)acceptNative}, -}; - -int register_android_bluetooth_RfcommSocket(JNIEnv *env) { - return AndroidRuntime::registerNativeMethods(env, - "android/bluetooth/RfcommSocket", sMethods, NELEM(sMethods)); -} - -} /* namespace android */ |